title: |
author: - Clovis Deletre - Charles Vitry date: output: html_notebook: theme: cerulean number_sections: no toc: yes toc_float: true editor_options: markdown: wrap: 72



Introduction

Nous souhaitons réalisé l’étude d’une série temporelle et faire des prévisions sur celle-ci.

Cette série temporelle est le trafic mensuel d’une Compagnie aérienne de janvier 2011 à août 2019.

Nos prévisions portent sur les 8 mois de l’année 2019

Représentation graphique de la série.

Import des données

Import de la base, on sélectionne la colonne des valeurs

library(readr)
data <- read_delim("Trafic-voyageurs.csv", 
    delim = ";", locale = locale(encoding = "ISO-8859-1"))
Rows: 104 Columns: 2
-- Column specification --------------------------------------------------------------------------------------------------------------------------
Delimiter: ";"
chr (1): dates
dbl (1): trafic

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
data_value <- data[,2]
summary(data)
      ds                  y         
 Length:104         Min.   :220876  
 Class :character   1st Qu.:297154  
 Mode  :character   Median :355178  
                    Mean   :354651  
                    3rd Qu.:407331  
                    Max.   :505190  

Création de notre série temporelle

Nous représentons nos données sous forme de série temporelle.

Une série temporelle est un ensemble de métrique mésurée sur des intervalles de temps réguliers.

Création de la série chronologique avec la librairie TSstudio :

  • start : année de début,
  • frequency : nbr de valeur par an => on en fréquence mensuelle donc 12
library(TSstudio)
data_ts <- ts(data_value, start=2011, frequency=12)
plot_1_TimeSeries(data_ts)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attachement du package : ‘plotly’

L'objet suivant est masqué depuis ‘package:ggplot2’:

    last_plot

L'objet suivant est masqué depuis ‘package:stats’:

    filter

L'objet suivant est masqué depuis ‘package:graphics’:

    layout

Séparation jeu de données

#revoir l affichage car ca prend pas en compte tt 2019
data_ts_train <- window(data_ts, start = c(2011, 1), end = c(2018,12))
data_ts_test <- window(data_ts, start= c(2019,1), end = c(2019,8))

names(data)[1] <- "ds"
names(data)[2] <- "y"
data_train <- data[1:96,]
data_test <- data[97:104,]


plot(data_ts, xlim=c(2011,2020))
lines(data_ts_test, col=3)
legend("topleft", lty = 1, col=c(1,3), legend=c("Série chronologique Train", "Série chronologique Test"))

-> strong trend -> patern qui se repete, saisonnalité ?

Représentation de la saisonnalité

Analyse de la saisonnalité en superposant chaque année (par mois):

-> en supprimant la tendance on voit bien la saisonnalité => saisonnalité régulière

Analyse de notre série temporelle

Chaque point de notre série temporelle peut être exprimer comme une somme ou un produit de 3 composantes : - Saisonnalité (St), - Tendance (Tt), - Erreur (ϵt),

Yt=St+Tt+ϵt ou Yt=St×Tt×ϵt

La stationnarité d’une série signifique que le processus qui génère la série ne change pas dans le temps. Cela ne veut pas dire que la série ne change pas dans le temps, mais que la façon dont elle change, n’est pas modifié dans le temps.

Testons si la série est stationnaire :

library(tseries)
Warning: le package ‘tseries’ a été compilé avec la version R 4.1.3

    ‘tseries’ version: 0.10-51

    ‘tseries’ is a package for time series analysis and
    computational finance.

    See ‘library(help="tseries")’ for details.
adf.test(data_ts)
Warning in adf.test(data_ts) : p-value smaller than printed p-value

    Augmented Dickey-Fuller Test

data:  data_ts
Dickey-Fuller = -5.4857, Lag order = 4, p-value = 0.01
alternative hypothesis: stationary
kpss.test(data_ts)
Warning in kpss.test(data_ts) : p-value smaller than printed p-value

    KPSS Test for Level Stationarity

data:  data_ts
KPSS Level = 2.0803, Truncation lag parameter = 4,
p-value = 0.01

Donc notre série est bien stationnaire et peut être étudiée facilement.

ggseasonplot(data_ts)

data_ts_without_trend = diff(data_ts)
ggseasonplot(data_ts_without_trend)

Représentation des décompositions possibles

DECOMPOSITION : additive / Multiplicative Ts = Trend + Seasonal + Random / Ts = Trend * Seasonal * Random

decomposed_data <- decompose(data_ts_train, type="additive")
plot(decomposed_data$trend)

plot(decomposed_data$seasonal)

plot(decomposed_data$random)


boxplot(data_ts ~ cycle(data_ts))

-> on distingue des saisonnalités => faire régression ca n’a pas de sens => modèle de Buys Ballot

-> bonne repartition du bruit -> quelques outliers

checkresiduals(remainder(decomposed_data))
Warning in modeldf.default(object) :
  Could not find appropriate degrees of freedom for this model.

On a tendances + saisonnalité

Modèles espace-état

  • meanf : Average Method : prend la valeur moyenne de toute les observations pour toutes les prédictions,
  • naive : Naive Method : prend la dernière observation pour toutes les prédictions,
  • drift : Drift Method : prend la première et la dernière observations et trace une lignes entre les deux, on utilise la courbe pour les prédictions,
  • snaive : Seasonal Naive Forecast : Prend la dernière valeur de la saison précédente comme prédiction (ex : sept 2018 = sep 2019 + erreur)
library(forecast)
mean <- meanf(data_ts_train, h=8)
naivem <- naive(data_ts_train, h=8)
driftm <- rwf(data_ts_train, h=8, drif=T)
snaivem <- snaive(data_ts_train, h=8)
plot(mean, plot.conf = F, main="")
Warning in plot.window(xlim, ylim, log, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in title(main = main, xlab = xlab, ylab = ylab, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in axis(1, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in axis(2, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in box(...) : "plot.conf" n'est pas un paramètre graphique
lines(naivem$mean, col=2, lty=1)
lines(driftm$mean, col=5, lty=1)
lines(snaivem$mean, col = 4, lty=1)
legend("topleft", lty=1, col=c(1,2,3,4), legend=c("Mean Method", "Naive Method", "Drif Method", "Seasonal Naive"))



#comparaison :
plot(snaivem, plot.conf = F, main="")
Warning in plot.window(xlim, ylim, log, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in title(main = main, xlab = xlab, ylab = ylab, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in axis(1, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in axis(2, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in box(...) : "plot.conf" n'est pas un paramètre graphique
lines(data_ts_test, col = 6, lty=1, lwd=3)


plot(driftm, plot.conf = F, main="")
Warning in plot.window(xlim, ylim, log, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in title(main = main, xlab = xlab, ylab = ylab, ...) :
  "plot.conf" n'est pas un paramètre graphique
Warning in axis(1, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in axis(2, ...) : "plot.conf" n'est pas un paramètre graphique
Warning in box(...) : "plot.conf" n'est pas un paramètre graphique
lines(data_ts_test, col = 6, lty=1, lwd=3)

On regarde : MAE : Mean Absolute Error : RMSE : Root Mean Squarred Error

MASE : Mean Absolute Scaled Error : MAPE : Mean Absolute Percentage Error :

res = pred - val MAE = sum(abs(res))/length(val) RSS = sum(res^2) MSE = RSS/length(val) RMSE = sqrt(MSE)

La plus populaire est la MAPE

MAPE(y_pred, y_true)

$MAPE = (1/n) * Σ(|actual – forecast| / |actu0al|) * 10

“a MAPE value of 6% means that the average difference between the forecasted value and the actual value is 6%”

print(summary(mean))

Forecast method: Mean

Model Information:
$mu
[1] 346667.1

$mu.se
[1] 6731.642

$sd
[1] 65956.35

$bootstrap
[1] FALSE

$call
meanf(y = data_ts_train, h = 8)

attr(,"class")
[1] "meanf"

Error measures:
                       ME     RMSE      MAE       MPE     MAPE    MASE      ACF1
Training set 1.941958e-11 65611.93 55535.08 -3.855657 17.01186 2.16177 0.8254447

Forecasts:
checkresiduals(mean)

    Ljung-Box test

data:  Residuals from Mean
Q* = 731.64, df = 18, p-value < 2.2e-16

Model df: 1.   Total lags used: 19

accuracy(mean, data_ts_test)
                       ME      RMSE       MAE       MPE     MAPE     MASE      ACF1 Theil's U
Training set 1.941958e-11  65611.93  55535.08 -3.855657 17.01186 2.161770 0.8254447        NA
Test set     1.037870e+05 110031.92 103787.04 22.486144 22.48614 4.040036 0.0485288  2.517689
print(summary(naivem))

Forecast method: Naive method

Model Information:
Call: naive(y = data_ts_train, h = 8) 

Residual sd: 36679.9508 

Error measures:
                   ME     RMSE      MAE         MPE     MAPE     MASE       ACF1
Training set 1896.811 36679.95 29013.27 -0.02007386 8.597313 1.129377 -0.2744236

Forecasts:
checkresiduals(naivem)

    Ljung-Box test

data:  Residuals from Naive method
Q* = 248.52, df = 19, p-value < 2.2e-16

Model df: 0.   Total lags used: 19

accuracy(naivem, data_ts_test)
                    ME     RMSE      MAE         MPE     MAPE     MASE       ACF1 Theil's U
Training set  1896.811 36679.95 29013.27 -0.02007386 8.597313 1.129377 -0.2744236        NA
Test set     24357.125 43915.19 38328.62  4.72582164 8.499751 1.491988  0.0485288  1.063155
print(summary(driftm))

Forecast method: Random walk with drift

Model Information:
Call: rwf(y = data_ts_train, h = 8, drift = T) 

Drift: 1896.8105  (se 3778.1861)
Residual sd: 36825.2032 

Error measures:
                       ME     RMSE      MAE        MPE     MAPE    MASE       ACF1
Training set 2.297696e-11 36630.87 28899.04 -0.5861884 8.591266 1.12493 -0.2744236

Forecasts:
checkresiduals(driftm)

    Ljung-Box test

data:  Residuals from Random walk with drift
Q* = 248.52, df = 18, p-value < 2.2e-16

Model df: 1.   Total lags used: 19

accuracy(driftm, data_ts_test)
                       ME     RMSE      MAE        MPE     MAPE     MASE        ACF1 Theil's U
Training set 2.297696e-11 36630.87 28899.04 -0.5861884 8.591266 1.124930 -0.27442358        NA
Test set     1.582148e+04 41314.60 33586.60  2.7843152 7.582963 1.307399  0.06907259  1.007801
print(summary(snaivem))

Forecast method: Seasonal naive method

Model Information:
Call: snaive(y = data_ts_train, h = 8) 

Residual sd: 28666.7301 

Error measures:
                   ME     RMSE      MAE      MPE     MAPE MASE      ACF1
Training set 25337.46 28666.73 25689.63 7.101745 7.207375    1 0.2695124

Forecasts:
checkresiduals(snaivem)

    Ljung-Box test

data:  Residuals from Seasonal naive method
Q* = 35.426, df = 19, p-value = 0.0124

Model df: 0.   Total lags used: 19

accuracy(snaivem, data_ts_test)
                   ME     RMSE      MAE      MPE     MAPE      MASE       ACF1 Theil's U
Training set 25337.46 28666.73 25689.63 7.101745 7.207375 1.0000000  0.2695124        NA
Test set     14263.38 22148.43 16960.88 3.053421 3.648407 0.6602226 -0.5427745 0.4792835

Etude du Modèle de Buys-Ballot

Modèle

https://mpra.ub.uni-muenchen.de/77718/1/MPRA_paper_77718.pdf page 175

L’approche de BUYS-BALLOT consiste à introduire des variables indicatrices correspondant à chaque saison définit par le cycle d’observation. Pour les données trimestrielles, on intègre 4 variables indicatrices. Et pour les données mensuelles, on intègre 12 variables indicatrices.

Le modèle doit alors être estimé (sans constante) avec ces variables indicatrices.

Prédiction des valeurs de 2019

Préparation des données.

Annees=as.numeric(time(data_ts_train))
ts_DataFrame =data.frame(trafic=data_ts_train,X=as.numeric(Annees))

Création du modèle

Regression <- lm(trafic~X,data = ts_DataFrame)

\(Xt = Zt + St + \mu t\)

La tendance Prédiction sur les données futurs.

tendance=predict(Regression)

AnneeMoisNumericFutur=seq(max(Annees)+1/12,length=8,by=1/12)  #les 10 prochains mois

tendance2=predict(Regression, newdata=data.frame(X=AnneeMoisNumericFutur)) 
ts_DataFrame$trafic_residual <- residuals(Regression)

Définissons le mois

ts_DataFrame$mois <- round(ts_DataFrame$X - trunc(ts_DataFrame$X),digit=4)

Création du 2nd modèle avec les mois

Regression2 =lm(trafic_residual~0+as.factor(mois),data=ts_DataFrame)

Prédiction de la saisonnalité

prediction2 =predict(Regression2)

Prédiction sur les mois

MoisNumeric= round(AnneeMoisNumericFutur - trunc(AnneeMoisNumericFutur
                     ),4)
Prediction3 =predict( Regression2, newdata= data.frame(mois=MoisNumeric))

Calculons une région de confiance avec l’erreur d’ajustement

ResidusRegression2=residuals(Regression2)
hist(ResidusRegression2)

1.96*sqrt(var(ResidusRegression2))
[1] 19226.16

Auto corrélation de la série temporelle

L’autocorrélation de notre série temporelle correspond à la corrélation entre une mesure du trafic \(t\) et les mesures précédentes \(t - k\) ou les mesures suivantes \(t + k\).

L’auto covariance d’une variable \(Xt\) de moyenne \(\mu\) et d’écart type \(\sigma\) à un décalage \(k\) est donné par la formule

\(\gamma_k= E((X_t-\mu)(X_{t+k}-\mu))\)

On en déduit l’autocorrélation correspondante :

\(\rho_k=\frac{\gamma_k}{\sigma^2}\)

Affichons les autocorrélations de la séries grâce à un corrélogramme

ACF_Sur_Valeurs_Predites <- acf(prediction2)

Il est normal que la série soit autocorrélé totalement à elle avec un décalage nulle.

On observe une corrélation forte (0.87) avec un décalage (lag) de 12, cela correspond bien à une saisonnalité annuelle.

print(data.frame(ACF_Sur_Valeurs_Predites$lag,ACF_Sur_Valeurs_Predites$acf)[1:13,])

Recalculons la valeur d’auto-corrélation obtenu en appliquant la formule.

Observons l’application de la formule, en choisissant un décalage de 12

#Constantes
Nombre_Observations=96
decalage=12

#Estimations
moyenneMu=mean(prediction2)
sdSigma=sd(prediction2)


Serie1=prediction2[(decalage+1): 96   ]
Serie2=prediction2[   1 :(96-decalage)]

GammaDecalage12=mean((Serie1-moyenneMu)*(Serie2-moyenneMu))*((Nombre_Observations-decalage)/(Nombre_Observations))

RhoDecalage12=GammaDecalage12/(sdSigma^2)
RhoDecalage12
[1] 0.8658622

Le résultat obtenu est correct. L’auto corrélation avec un décalage de 12 est donc très forte.

De plus cette auto corrélation étant positive, cela indique une tendance croissante.

la deuxième plus forte corrélation est obsersé avec un décalage de 5, observons cela graphiquement

plot  ( 1:length(prediction2),   prediction2,type="l")
points((1:length(prediction2))-5,prediction2,type="l",col="red")

Cette corrélation est peu pertinente.

print(data.frame(ACF_Sur_Valeurs_Predites$lag,ACF_Sur_Valeurs_Predites$acf)[1:13,])

Après avoir étudier les auto-corrélations sur l’ensemble du modèle, Observons les auto-corrélations sur les résidus du modèle de Buys-Ballot.

  • Texte pour dire que les accidents ne doivent pas être corrélés *
plot(acf(ResidusRegression2))

Pour notre modèle, il n’y a aucune auto-corrélation significative. (symbolisé par la ligne bleu)

Comparaison des prédictions et des valeurs réelles

Affichage de la tendance

Buys_ballot_plot_tendance <- plot(data_ts,
                         main = "Application du modèle de Buys_Ballot",
                         xlab = "Années",
                         ylab = "Nombre de Voyageurs") 

#droite de tendance
lines(Annees,tendance,col="blue",lwd=2)  

#prédiction de la tendance futur
lines(AnneeMoisNumericFutur,tendance2,col="red")

NA
NA

Affichage du modèle de Buys Ballot


Buys_ballot_plot <- plot(data_ts,
                         main = "Application du modèle de Buys_Ballot",
                         xlab = "Années",
                         ylab = "Nombre de Voyageurs") 



#prédiction du modèle de Buys ballot
lines(Annees,tendance+prediction2,col="blue",lwd=2)

#Interval de confiance
 polygon(c(AnneeMoisNumericFutur,rev(AnneeMoisNumericFutur)),
 c(tendance2+Prediction3-1.96*sqrt(var(ResidusRegression2)),
 rev(tendance2+Prediction3+1.96*sqrt(var(ResidusRegression2)))),
 col="cadetblue1",border=NA)
 
 #Prediction des valeurs
 lines(AnneeMoisNumericFutur,tendance2+Prediction3,col="blue",lwd=2)
 
 
 lines(data_ts_test,col="black",lwd=3)

Affichage de la prédiction sur les 8 mois de 2020


Buys_ballot_plot <- plot(data_ts_test,
                         main = "Application du modèle de Buys_Ballot",
                         xlab = "Années",
                         ylab = "Nombre de Voyageurs") 



#prédiction du modèle de Buys ballot
lines(Annees,tendance+prediction2,col="blue",lwd=2)

#Interval de confiance
 polygon(c(AnneeMoisNumericFutur,rev(AnneeMoisNumericFutur)),
 c(tendance2+Prediction3-1.96*sqrt(var(ResidusRegression2)),
 rev(tendance2+Prediction3+1.96*sqrt(var(ResidusRegression2)))),
 col="cadetblue1",border=NA)
 
 #Prediction des valeurs
 lines(AnneeMoisNumericFutur,tendance2+Prediction3,col="blue",lwd=2)
 
 
 lines(data_ts_test,col="black",lwd=3)

Préparation DataFrame pour affichage ggplot

DataAffichageGGplot = as.data.frame(data_ts)
DataAffichageGGplot$Annees = c(Annees, AnneeMoisNumericFutur)
DataAffichageGGplot$AnneesRound = round(DataAffichageGGplot$Annees)
DataAffichageGGplot$PredictionTendance = c(tendance ,tendance2)
DataAffichageGGplot$BuysBalotModele = c(tendance+prediction2,tendance2+Prediction3 )

Reproduisons les graphiques avec ggplot2 pour un résultat plus professsionnel.

library(ggplot2)
library(ggthemes)

p <- ggplot(data =DataAffichageGGplot, aes(x = Annees) ) + 

  geom_line(aes(y = trafic ), size = 0.9, alpha = 0.7)+

  #geom_line(aes(y = PredictionTendance), size = 0.6, alpha = 0.85,linetype="twodash" )+
  
  geom_line(aes(y = BuysBalotModele), size = 1.2, alpha = 0.6, color = "blue")+
  labs(title = "Application du modèle de Buys_Ballot",
       x="Années",
         y= "Nombre de Voyageurs")+
theme_fivethirtyeight()+
  theme(axis.title = element_text(), text = element_text(family = "Rubik")) 

#sur l'année 2019
p2 <- ggplot(data =DataAffichageGGplot, aes(x = Annees) ) + 
  geom_line(aes(y = trafic ), size = 1.2, alpha = 0.7)+
  geom_line(aes(y = BuysBalotModele), size = 1.4, alpha = 0.6, color = "blue")+
theme_fivethirtyeight()+
   xlim (2019.0, 2019.583) +
  ylim (435000, 520000) 


#Ajout zoom sur 2019
p + 
  annotation_custom(ggplotGrob(p2), xmin = 2015, xmax = 2020, ymin = 50000, ymax = 280000) +
  geom_rect(aes(xmin = 2015, xmax = 2020, ymin = 50000, ymax = 280000), color='black', linetype='dashed', alpha=0) 

NA
NA
NA

Nous avons réussi à ajuster une droite de régression. on remarque que la prédiction semble bien correspondre à la réalité si on fait abstraction du dernier mois où le nombre de voyageurs a bien plus chuté que la prédiction du modèle de Buys-Balot.

Comparons avec un ajustement local réalisé par lissage moyennes mobiles.

Comparaison avec les valeurs observées

Lissage moyenne mobile

Définition

Mettre belle formule en latex ici

Choix Moyenne mobiles

Conservation & Annulation

Lissage exponentielle

Lissage simple

fcst_se <- ses(data_ts_train, h = 8)
print(summary(fcst_se))

Forecast method: Simple exponential smoothing

Model Information:
Simple exponential smoothing 

Call:
 ses(y = data_ts_train, h = 8) 

  Smoothing parameters:
    alpha = 0.2559 

  Initial states:
    l = 258126.0245 

  sigma:  31480.96

     AIC     AICc      BIC 
2430.727 2430.988 2438.420 

Error measures:
                   ME     RMSE      MAE      MPE     MAPE     MASE      ACF1
Training set 7057.127 31151.31 25752.89 1.326234 7.684321 1.002462 0.0711143

Forecasts:
checkresiduals(fcst_se)

    Ljung-Box test

data:  Residuals from Simple exponential smoothing
Q* = 144.66, df = 17, p-value < 2.2e-16

Model df: 2.   Total lags used: 19

plot(fcst_se)
lines(data_ts_test, col="red")



df_se = as.data.frame(fcst_se)
predict_value_se <- df_se$`Point Forecast`
MAPE(predict_value_se, data_ts_test)*100
[1] 7.658334

Optimisation du modèle

Fit Exponential Smoothing model -> trouve le meilleur lissage expo

fit_ets <- ets(data_ts_train) 
print(summary(fit_ets))
ETS(A,A,A) 

Call:
 ets(y = data_ts_train) 

  Smoothing parameters:
    alpha = 0.1568 
    beta  = 1e-04 
    gamma = 1e-04 

  Initial states:
    l = 248267.1099 
    b = 2163.3982 
    s = -17928.3 -29535.73 9295.935 11005.81 -57117.85 -7708.17
           38272.64 14592.34 16899.53 34763.15 -7344.204 -5195.15

  sigma:  11014.45

     AIC     AICc      BIC 
2241.611 2249.458 2285.205 

Training set error measures:
                    ME     RMSE      MAE        MPE     MAPE      MASE       ACF1
Training set -458.6799 10054.77 7831.554 -0.2623253 2.371375 0.3048527 0.09626331
checkresiduals(fit_ets)

    Ljung-Box test

data:  Residuals from ETS(A,A,A)
Q* = 7.1794, df = 3, p-value = 0.06639

Model df: 16.   Total lags used: 19

fcst_ets <- forecast(fit_ets, h=8)
plot(fcst_ets)
lines(data_ts_test, col="red")



df_ets = as.data.frame(fcst_ets)
predict_value_ets = df_ets$`Point Forecast`
MAPE(predict_value_ets, data_ts_test)*100
[1] 3.005848

Modèle ARMA

A FAIRE

Modèle ARIMA / SAMIRA Automatique

ARIMA : AutoRegressive Integrated Moving Average

Le modèle ARIMA est une combinaison du modèle ARMA combiné à une différentiation (le Integrated)

Différentiation = rétirer les tendances -> tendance linéaire : une différenciation -> tendance quadradique : deux différenciations

Le modèle SARIMA est une combinaison du modèle ARIMA qui prend en compte la composante saisonniaire.

auto.arima prend en compte les saisonnalités, comme on peut le voir dans le modèle selectionné : (0,1,1)(0,1,1)[12]

# retourne les meilleurs paramètres 
# d=1 enleve la tendance
# D=1 enleve la saisonnalité 
# => avoir des données stationnaires
# trace : voir les résultats
fit_arima <- auto.arima(data_ts_train, d=1, D=1, stepwise = FALSE, approximation = FALSE, trace=TRUE)

 ARIMA(0,1,0)(0,1,0)[12]                    : 1846.398
 ARIMA(0,1,0)(0,1,1)[12]                    : 1833.134
 ARIMA(0,1,0)(0,1,2)[12]                    : 1835.211
 ARIMA(0,1,0)(1,1,0)[12]                    : 1833.056
 ARIMA(0,1,0)(1,1,1)[12]                    : 1835.09
 ARIMA(0,1,0)(1,1,2)[12]                    : Inf
 ARIMA(0,1,0)(2,1,0)[12]                    : 1835.207
 ARIMA(0,1,0)(2,1,1)[12]                    : 1837.012
 ARIMA(0,1,0)(2,1,2)[12]                    : 1836.461
 ARIMA(0,1,1)(0,1,0)[12]                    : 1814.951
 ARIMA(0,1,1)(0,1,1)[12]                    : 1801.155
 ARIMA(0,1,1)(0,1,2)[12]                    : 1803.362
 ARIMA(0,1,1)(1,1,0)[12]                    : 1803.592
 ARIMA(0,1,1)(1,1,1)[12]                    : 1803.361
 ARIMA(0,1,1)(1,1,2)[12]                    : Inf
 ARIMA(0,1,1)(2,1,0)[12]                    : 1805.004
 ARIMA(0,1,1)(2,1,1)[12]                    : 1805.397
 ARIMA(0,1,1)(2,1,2)[12]                    : Inf
 ARIMA(0,1,2)(0,1,0)[12]                    : 1816.915
 ARIMA(0,1,2)(0,1,1)[12]                    : 1803.033
 ARIMA(0,1,2)(0,1,2)[12]                    : 1805.296
 ARIMA(0,1,2)(1,1,0)[12]                    : 1805.702
 ARIMA(0,1,2)(1,1,1)[12]                    : 1805.295
 ARIMA(0,1,2)(1,1,2)[12]                    : Inf
 ARIMA(0,1,2)(2,1,0)[12]                    : 1807.026
 ARIMA(0,1,2)(2,1,1)[12]                    : 1807.441
 ARIMA(0,1,3)(0,1,0)[12]                    : 1817.787
 ARIMA(0,1,3)(0,1,1)[12]                    : Inf
 ARIMA(0,1,3)(0,1,2)[12]                    : Inf
 ARIMA(0,1,3)(1,1,0)[12]                    : Inf
 ARIMA(0,1,3)(1,1,1)[12]                    : Inf
 ARIMA(0,1,3)(2,1,0)[12]                    : Inf
 ARIMA(0,1,4)(0,1,0)[12]                    : 1820.052
 ARIMA(0,1,4)(0,1,1)[12]                    : Inf
 ARIMA(0,1,4)(1,1,0)[12]                    : Inf
 ARIMA(0,1,5)(0,1,0)[12]                    : Inf
 ARIMA(1,1,0)(0,1,0)[12]                    : 1825.579
 ARIMA(1,1,0)(0,1,1)[12]                    : 1812.512
 ARIMA(1,1,0)(0,1,2)[12]                    : 1814.657
 ARIMA(1,1,0)(1,1,0)[12]                    : 1813.2
 ARIMA(1,1,0)(1,1,1)[12]                    : 1814.614
 ARIMA(1,1,0)(1,1,2)[12]                    : 1816.192
 ARIMA(1,1,0)(2,1,0)[12]                    : 1815.227
 ARIMA(1,1,0)(2,1,1)[12]                    : Inf
 ARIMA(1,1,0)(2,1,2)[12]                    : 1817.796
 ARIMA(1,1,1)(0,1,0)[12]                    : 1816.841
 ARIMA(1,1,1)(0,1,1)[12]                    : 1802.853
 ARIMA(1,1,1)(0,1,2)[12]                    : 1805.117
 ARIMA(1,1,1)(1,1,0)[12]                    : 1805.653
 ARIMA(1,1,1)(1,1,1)[12]                    : Inf
 ARIMA(1,1,1)(1,1,2)[12]                    : Inf
 ARIMA(1,1,1)(2,1,0)[12]                    : Inf
 ARIMA(1,1,1)(2,1,1)[12]                    : Inf
 ARIMA(1,1,2)(0,1,0)[12]                    : 1819.234
 ARIMA(1,1,2)(0,1,1)[12]                    : 1805.22
 ARIMA(1,1,2)(0,1,2)[12]                    : 1807.539
 ARIMA(1,1,2)(1,1,0)[12]                    : 1807.381
 ARIMA(1,1,2)(1,1,1)[12]                    : 1807.538
 ARIMA(1,1,2)(2,1,0)[12]                    : 1808.925
 ARIMA(1,1,3)(0,1,0)[12]                    : 1820.05
 ARIMA(1,1,3)(0,1,1)[12]                    : 1806.055
 ARIMA(1,1,3)(1,1,0)[12]                    : 1808.732
 ARIMA(1,1,4)(0,1,0)[12]                    : Inf
 ARIMA(2,1,0)(0,1,0)[12]                    : 1824.435
 ARIMA(2,1,0)(0,1,1)[12]                    : 1811.07
 ARIMA(2,1,0)(0,1,2)[12]                    : 1813.287
 ARIMA(2,1,0)(1,1,0)[12]                    : 1811.619
 ARIMA(2,1,0)(1,1,1)[12]                    : 1813.247
 ARIMA(2,1,0)(1,1,2)[12]                    : Inf
 ARIMA(2,1,0)(2,1,0)[12]                    : 1813.821
 ARIMA(2,1,0)(2,1,1)[12]                    : 1815.872
 ARIMA(2,1,1)(0,1,0)[12]                    : Inf
 ARIMA(2,1,1)(0,1,1)[12]                    : Inf
 ARIMA(2,1,1)(0,1,2)[12]                    : Inf
 ARIMA(2,1,1)(1,1,0)[12]                    : Inf
 ARIMA(2,1,1)(1,1,1)[12]                    : Inf
 ARIMA(2,1,1)(2,1,0)[12]                    : Inf
 ARIMA(2,1,2)(0,1,0)[12]                    : Inf
 ARIMA(2,1,2)(0,1,1)[12]                    : Inf
 ARIMA(2,1,2)(1,1,0)[12]                    : Inf
 ARIMA(2,1,3)(0,1,0)[12]                    : Inf
 ARIMA(3,1,0)(0,1,0)[12]                    : 1823.646
 ARIMA(3,1,0)(0,1,1)[12]                    : 1808.49
 ARIMA(3,1,0)(0,1,2)[12]                    : 1810.542
 ARIMA(3,1,0)(1,1,0)[12]                    : 1808.594
 ARIMA(3,1,0)(1,1,1)[12]                    : 1810.321
 ARIMA(3,1,0)(2,1,0)[12]                    : 1810.708
 ARIMA(3,1,1)(0,1,0)[12]                    : Inf
 ARIMA(3,1,1)(0,1,1)[12]                    : Inf
 ARIMA(3,1,1)(1,1,0)[12]                    : Inf
 ARIMA(3,1,2)(0,1,0)[12]                    : Inf
 ARIMA(4,1,0)(0,1,0)[12]                    : 1823.996
 ARIMA(4,1,0)(0,1,1)[12]                    : 1810.199
 ARIMA(4,1,0)(1,1,0)[12]                    : 1810.845
 ARIMA(4,1,1)(0,1,0)[12]                    : Inf
 ARIMA(5,1,0)(0,1,0)[12]                    : 1825.055



 Best model: ARIMA(0,1,1)(0,1,1)[12]                    
print(summary(fit_arima))
Series: data_ts_train 
ARIMA(0,1,1)(0,1,1)[12] 

Coefficients:
          ma1     sma1
      -0.7675  -0.5465
s.e.   0.0977   0.1295

sigma^2 = 138827719:  log likelihood = -897.43
AIC=1800.85   AICc=1801.16   BIC=1808.11

Training set error measures:
                   ME     RMSE      MAE       MPE     MAPE      MASE       ACF1
Training set 805.2378 10822.93 7747.841 0.2158443 2.213481 0.3015941 0.03453594
checkresiduals(fit_arima)

    Ljung-Box test

data:  Residuals from ARIMA(0,1,1)(0,1,1)[12]
Q* = 10.898, df = 17, p-value = 0.8618

Model df: 2.   Total lags used: 19

fcst_arima <- forecast(fit_arima, h=8)
plot(fcst_arima)
lines(data_ts_test, col='red')



df_arima = as.data.frame(fcst_arima)
predict_value_arima = df_arima$`Point Forecast`
MAPE(predict_value_arima, data_ts_test)*100
[1] 2.814135

PROPHET

Préparation données

library(zoo)

Attachement du package : ‘zoo’

Les objets suivants sont masqués depuis ‘package:base’:

    as.Date, as.Date.numeric
data_train$ds <- as.Date( as.yearmon(time(data_ts_train)))

A COMMENTER ET A FAIRE FONCTIONNER SURTT (changement de la forme des dates?)

library(prophet)
model_prophet <- prophet(data_train)
Disabling weekly seasonality. Run prophet with weekly.seasonality=TRUE to override this.
Disabling daily seasonality. Run prophet with daily.seasonality=TRUE to override this.
forecast_prophet <- make_future_dataframe(model_prophet, periods = 8, freq = 'month')
AAPLfc <- predict(model_prophet, forecast_prophet)
tail(AAPLfc[c("ds", "yhat", "yhat_lower", "yhat")])


dyplot.prophet(model_prophet, AAPLfc)



data_pp <- subset(AAPLfc, select=c("yhat"))
data_pp_ts <- ts(data_tttt, start=2011, frequency=12)
data_pp_ts_w <- window(data_pp_ts, start= c(2019,1), end = c(2019,8))



plot(data_ts)
lines(data_pp_ts_w, col="red")


MAPE(data_pp_ts_w, data_ts_test)*100
[1] 3.396584

LSTM


scale_factors <- c(mean(data$y), sd(data$y))
scaled_train <- data %>%
    dplyr::select(y) %>%
    dplyr::mutate(y = (y - scale_factors[1]) / scale_factors[2])
scaled_train



prediction <- 12
lag <- prediction

On veut prendre l’année précedente pour apprendre > lag de 12, en réalité ca fait 12 - 1 pour avoir à chaque prédiction basée sur 12 valeurs

puis en transforme en array 3D car le modèle LSTM prendre un tensor de format 3D [samples, timesteps, features] samples : nbr d’observation par batchs timesteps : lag features : nbr de valeur predites

scaled_train <- as.matrix(scaled_train)
 
# we lag the data 11 times and arrange that into columns
x_train_data <- t(sapply(
    1:(length(scaled_train) - lag - prediction + 1),
    function(x) scaled_train[x:(x + lag - 1), 1]
  ))
 
# now we transform it into 3D form
x_train_arr <- array(
    data = as.numeric(unlist(x_train_data)),
    dim = c(
        nrow(x_train_data),
        lag,
        1
    )
)

#(x_train_data)
#length(x_train_arr)
#head(x_train_arr)
y_train_data <- t(sapply(
    (1 + lag):(length(scaled_train) - prediction + 1),
    function(x) scaled_train[x:(x + prediction - 1)]
))

y_train_arr <- array(
    data = as.numeric(unlist(y_train_data)),
    dim = c(
        nrow(y_train_data),
        prediction,
        1
    )
)

#head(y_train_data)
#head(y_train_arr)
x_test <- data$y[(nrow(scaled_train) - prediction + 1):nrow(scaled_train)]

x_test_scaled <- (x_test - scale_factors[1]) / scale_factors[2]

x_pred_arr <- array(
    data = x_test_scaled,
    dim = c(
        1,
        lag,
        1
    )
)
lstm_model <- keras_model_sequential()

lstm_model %>%
  layer_lstm(units = 50, # size of the layer
       batch_input_shape = c(1, 12, 1), # batch size, timesteps, features
       return_sequences = TRUE,
       stateful = TRUE) %>%
  # fraction of the units to drop for the linear transformation of the inputs
  layer_dropout(rate = 0.5) %>%
  layer_lstm(units = 50,
        return_sequences = TRUE,
        stateful = TRUE) %>%
  layer_dropout(rate = 0.5) %>%
  time_distributed(keras::layer_dense(units = 1))

lstm_model %>%
    compile(loss = 'mae', optimizer = 'adam', metrics = 'accuracy')

summary(lstm_model)
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 lstm_7 (LSTM)               (1, 12, 50)               10400     
 dropout_7 (Dropout)         (1, 12, 50)               0         
 lstm_6 (LSTM)               (1, 12, 50)               20200     
 dropout_6 (Dropout)         (1, 12, 50)               0         
 time_distributed_3 (TimeDis  (1, 12, 1)               51        
 tributed)                                                       
=================================================================
Total params: 30,651
Trainable params: 30,651
Non-trainable params: 0
_________________________________________________________________
lstm_model %>% fit(
    x = x_train_arr,
    y = y_train_arr,
    batch_size = 1,
    epochs = 20,
    verbose = 1,
    shuffle = FALSE
)
Epoch 1/20

 1/81 [..............................] - ETA: 3:53 - loss: 1.2196 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.6508 - accuracy: 0.0000e+00  
19/81 [======>.......................] - ETA: 0s - loss: 0.5166 - accuracy: 0.0000e+00
28/81 [=========>....................] - ETA: 0s - loss: 0.4629 - accuracy: 0.0000e+00
38/81 [=============>................] - ETA: 0s - loss: 0.4150 - accuracy: 0.0000e+00
48/81 [================>.............] - ETA: 0s - loss: 0.4078 - accuracy: 0.0000e+00
58/81 [====================>.........] - ETA: 0s - loss: 0.4323 - accuracy: 0.0000e+00
68/81 [========================>.....] - ETA: 0s - loss: 0.4429 - accuracy: 0.0000e+00
77/81 [===========================>..] - ETA: 0s - loss: 0.4624 - accuracy: 0.0000e+00
81/81 [==============================] - 3s 6ms/step - loss: 0.4697 - accuracy: 0.0000e+00

81/81 [==============================] - 4s 12ms/step - loss: 0.4697 - accuracy: 0.0000e+00
Epoch 2/20

 1/81 [..............................] - ETA: 0s - loss: 1.7441 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 1.0279 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.7254 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.6267 - accuracy: 0.0000e+00
33/81 [===========>..................] - ETA: 0s - loss: 0.5566 - accuracy: 0.0000e+00
41/81 [==============>...............] - ETA: 0s - loss: 0.5079 - accuracy: 0.0000e+00
50/81 [=================>............] - ETA: 0s - loss: 0.4753 - accuracy: 0.0000e+00
59/81 [====================>.........] - ETA: 0s - loss: 0.4660 - accuracy: 0.0000e+00
67/81 [=======================>......] - ETA: 0s - loss: 0.4515 - accuracy: 0.0000e+00
71/81 [=========================>....] - ETA: 0s - loss: 0.4478 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.4429 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.4419 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.4419 - accuracy: 0.0000e+00
Epoch 3/20

 1/81 [..............................] - ETA: 0s - loss: 1.7155 - accuracy: 0.0000e+00
 8/81 [=>............................] - ETA: 0s - loss: 0.6954 - accuracy: 0.0000e+00
15/81 [====>.........................] - ETA: 0s - loss: 0.5548 - accuracy: 0.0000e+00
24/81 [=======>......................] - ETA: 0s - loss: 0.5052 - accuracy: 0.0000e+00
33/81 [===========>..................] - ETA: 0s - loss: 0.4540 - accuracy: 0.0000e+00
41/81 [==============>...............] - ETA: 0s - loss: 0.4305 - accuracy: 0.0000e+00
50/81 [=================>............] - ETA: 0s - loss: 0.4080 - accuracy: 0.0000e+00
59/81 [====================>.........] - ETA: 0s - loss: 0.4005 - accuracy: 0.0000e+00
67/81 [=======================>......] - ETA: 0s - loss: 0.4002 - accuracy: 0.0000e+00
76/81 [===========================>..] - ETA: 0s - loss: 0.3985 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3975 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3975 - accuracy: 0.0000e+00
Epoch 4/20

 1/81 [..............................] - ETA: 0s - loss: 1.3672 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.5138 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.4371 - accuracy: 0.0000e+00
27/81 [=========>....................] - ETA: 0s - loss: 0.4106 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.3880 - accuracy: 0.0000e+00
46/81 [================>.............] - ETA: 0s - loss: 0.3691 - accuracy: 0.0000e+00
55/81 [===================>..........] - ETA: 0s - loss: 0.3653 - accuracy: 0.0000e+00
63/81 [======================>.......] - ETA: 0s - loss: 0.3649 - accuracy: 0.0000e+00
71/81 [=========================>....] - ETA: 0s - loss: 0.3666 - accuracy: 0.0000e+00
79/81 [============================>.] - ETA: 0s - loss: 0.3698 - accuracy: 0.0000e+00
81/81 [==============================] - 0s 6ms/step - loss: 0.3701 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3701 - accuracy: 0.0000e+00
Epoch 5/20

 1/81 [..............................] - ETA: 0s - loss: 1.2701 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.5676 - accuracy: 0.0000e+00
19/81 [======>.......................] - ETA: 0s - loss: 0.4692 - accuracy: 0.0000e+00
27/81 [=========>....................] - ETA: 0s - loss: 0.4338 - accuracy: 0.0000e+00
35/81 [===========>..................] - ETA: 0s - loss: 0.4071 - accuracy: 0.0000e+00
44/81 [===============>..............] - ETA: 0s - loss: 0.3883 - accuracy: 0.0000e+00
53/81 [==================>...........] - ETA: 0s - loss: 0.3734 - accuracy: 0.0000e+00
62/81 [=====================>........] - ETA: 0s - loss: 0.3700 - accuracy: 0.0000e+00
71/81 [=========================>....] - ETA: 0s - loss: 0.3725 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.3730 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3734 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3734 - accuracy: 0.0000e+00
Epoch 6/20

 1/81 [..............................] - ETA: 0s - loss: 1.1583 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.5097 - accuracy: 0.0000e+00
19/81 [======>.......................] - ETA: 0s - loss: 0.4409 - accuracy: 0.0000e+00
28/81 [=========>....................] - ETA: 0s - loss: 0.4065 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.3826 - accuracy: 0.0000e+00
45/81 [===============>..............] - ETA: 0s - loss: 0.3653 - accuracy: 0.0000e+00
54/81 [===================>..........] - ETA: 0s - loss: 0.3586 - accuracy: 0.0000e+00
63/81 [======================>.......] - ETA: 0s - loss: 0.3573 - accuracy: 0.0000e+00
72/81 [=========================>....] - ETA: 0s - loss: 0.3637 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.3686 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3684 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3684 - accuracy: 0.0000e+00
Epoch 7/20

 1/81 [..............................] - ETA: 0s - loss: 1.1450 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.5335 - accuracy: 0.0000e+00
17/81 [=====>........................] - ETA: 0s - loss: 0.4628 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.4280 - accuracy: 0.0000e+00
34/81 [===========>..................] - ETA: 0s - loss: 0.3954 - accuracy: 0.0000e+00
42/81 [==============>...............] - ETA: 0s - loss: 0.3783 - accuracy: 0.0000e+00
51/81 [=================>............] - ETA: 0s - loss: 0.3597 - accuracy: 0.0000e+00
60/81 [=====================>........] - ETA: 0s - loss: 0.3569 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.3515 - accuracy: 0.0000e+00
77/81 [===========================>..] - ETA: 0s - loss: 0.3500 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3508 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3508 - accuracy: 0.0000e+00
Epoch 8/20

 1/81 [..............................] - ETA: 0s - loss: 1.0118 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.4696 - accuracy: 0.0000e+00
17/81 [=====>........................] - ETA: 0s - loss: 0.4049 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.3854 - accuracy: 0.0000e+00
35/81 [===========>..................] - ETA: 0s - loss: 0.3585 - accuracy: 0.0000e+00
44/81 [===============>..............] - ETA: 0s - loss: 0.3440 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.3378 - accuracy: 0.0000e+00
61/81 [=====================>........] - ETA: 0s - loss: 0.3390 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.3371 - accuracy: 0.0000e+00
75/81 [==========================>...] - ETA: 0s - loss: 0.3338 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.3352 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3352 - accuracy: 0.0000e+00
Epoch 9/20

 1/81 [..............................] - ETA: 0s - loss: 0.8777 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.4511 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.4025 - accuracy: 0.0000e+00
27/81 [=========>....................] - ETA: 0s - loss: 0.3700 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.3482 - accuracy: 0.0000e+00
45/81 [===============>..............] - ETA: 0s - loss: 0.3335 - accuracy: 0.0000e+00
53/81 [==================>...........] - ETA: 0s - loss: 0.3257 - accuracy: 0.0000e+00
61/81 [=====================>........] - ETA: 0s - loss: 0.3264 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.3210 - accuracy: 0.0000e+00
78/81 [===========================>..] - ETA: 0s - loss: 0.3194 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3214 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3214 - accuracy: 0.0000e+00
Epoch 10/20

 1/81 [..............................] - ETA: 0s - loss: 0.8479 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.4344 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.3816 - accuracy: 0.0000e+00
27/81 [=========>....................] - ETA: 0s - loss: 0.3470 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.3260 - accuracy: 0.0000e+00
45/81 [===============>..............] - ETA: 0s - loss: 0.3100 - accuracy: 0.0000e+00
53/81 [==================>...........] - ETA: 0s - loss: 0.3050 - accuracy: 0.0000e+00
62/81 [=====================>........] - ETA: 0s - loss: 0.3033 - accuracy: 0.0000e+00
71/81 [=========================>....] - ETA: 0s - loss: 0.3024 - accuracy: 0.0000e+00
79/81 [============================>.] - ETA: 0s - loss: 0.3030 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.3026 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.3026 - accuracy: 0.0000e+00
Epoch 11/20

 1/81 [..............................] - ETA: 0s - loss: 0.6136 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.3721 - accuracy: 0.0000e+00
17/81 [=====>........................] - ETA: 0s - loss: 0.3475 - accuracy: 0.0000e+00
25/81 [========>.....................] - ETA: 0s - loss: 0.3264 - accuracy: 0.0000e+00
34/81 [===========>..................] - ETA: 0s - loss: 0.2992 - accuracy: 0.0000e+00
43/81 [==============>...............] - ETA: 0s - loss: 0.2771 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.2647 - accuracy: 0.0000e+00
60/81 [=====================>........] - ETA: 0s - loss: 0.2611 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.2602 - accuracy: 0.0000e+00
77/81 [===========================>..] - ETA: 0s - loss: 0.2607 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.2623 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2623 - accuracy: 0.0000e+00
Epoch 12/20

 1/81 [..............................] - ETA: 0s - loss: 0.9494 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.4115 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.3282 - accuracy: 0.0000e+00
27/81 [=========>....................] - ETA: 0s - loss: 0.2920 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.2721 - accuracy: 0.0000e+00
44/81 [===============>..............] - ETA: 0s - loss: 0.2522 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.2432 - accuracy: 0.0000e+00
61/81 [=====================>........] - ETA: 0s - loss: 0.2368 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.2347 - accuracy: 0.0000e+00
77/81 [===========================>..] - ETA: 0s - loss: 0.2336 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.2352 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2352 - accuracy: 0.0000e+00
Epoch 13/20

 1/81 [..............................] - ETA: 0s - loss: 0.5150 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.2720 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.2419 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.2285 - accuracy: 0.0000e+00
34/81 [===========>..................] - ETA: 0s - loss: 0.2291 - accuracy: 0.0000e+00
41/81 [==============>...............] - ETA: 0s - loss: 0.2230 - accuracy: 0.0000e+00
49/81 [=================>............] - ETA: 0s - loss: 0.2123 - accuracy: 0.0000e+00
57/81 [====================>.........] - ETA: 0s - loss: 0.2123 - accuracy: 0.0000e+00
65/81 [=======================>......] - ETA: 0s - loss: 0.2121 - accuracy: 0.0000e+00
74/81 [==========================>...] - ETA: 0s - loss: 0.2190 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.2206 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2206 - accuracy: 0.0000e+00
Epoch 14/20

 1/81 [..............................] - ETA: 0s - loss: 0.3170 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.2753 - accuracy: 0.0000e+00
16/81 [====>.........................] - ETA: 0s - loss: 0.2593 - accuracy: 0.0000e+00
24/81 [=======>......................] - ETA: 0s - loss: 0.2422 - accuracy: 0.0000e+00
32/81 [==========>...................] - ETA: 0s - loss: 0.2272 - accuracy: 0.0000e+00
40/81 [=============>................] - ETA: 0s - loss: 0.2234 - accuracy: 0.0000e+00
48/81 [================>.............] - ETA: 0s - loss: 0.2134 - accuracy: 0.0000e+00
55/81 [===================>..........] - ETA: 0s - loss: 0.2123 - accuracy: 0.0000e+00
63/81 [======================>.......] - ETA: 0s - loss: 0.2163 - accuracy: 0.0000e+00
70/81 [========================>.....] - ETA: 0s - loss: 0.2173 - accuracy: 0.0000e+00
79/81 [============================>.] - ETA: 0s - loss: 0.2241 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.2247 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2247 - accuracy: 0.0000e+00
Epoch 15/20

 1/81 [..............................] - ETA: 0s - loss: 0.3073 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.3156 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.2693 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.2407 - accuracy: 0.0000e+00
35/81 [===========>..................] - ETA: 0s - loss: 0.2330 - accuracy: 0.0000e+00
43/81 [==============>...............] - ETA: 0s - loss: 0.2203 - accuracy: 0.0000e+00
51/81 [=================>............] - ETA: 0s - loss: 0.2123 - accuracy: 0.0000e+00
60/81 [=====================>........] - ETA: 0s - loss: 0.2121 - accuracy: 0.0000e+00
68/81 [========================>.....] - ETA: 0s - loss: 0.2141 - accuracy: 0.0000e+00
76/81 [===========================>..] - ETA: 0s - loss: 0.2176 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.2180 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2180 - accuracy: 0.0000e+00
Epoch 16/20

 1/81 [..............................] - ETA: 1s - loss: 0.5290 - accuracy: 0.0000e+00
10/81 [==>...........................] - ETA: 0s - loss: 0.3024 - accuracy: 0.0000e+00
19/81 [======>.......................] - ETA: 0s - loss: 0.2603 - accuracy: 0.0000e+00
28/81 [=========>....................] - ETA: 0s - loss: 0.2308 - accuracy: 0.0000e+00
36/81 [============>.................] - ETA: 0s - loss: 0.2352 - accuracy: 0.0000e+00
44/81 [===============>..............] - ETA: 0s - loss: 0.2226 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.2132 - accuracy: 0.0000e+00
61/81 [=====================>........] - ETA: 0s - loss: 0.2121 - accuracy: 0.0000e+00
69/81 [========================>.....] - ETA: 0s - loss: 0.2138 - accuracy: 0.0000e+00
78/81 [===========================>..] - ETA: 0s - loss: 0.2214 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 6ms/step - loss: 0.2230 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2230 - accuracy: 0.0000e+00
Epoch 17/20

 1/81 [..............................] - ETA: 0s - loss: 0.3725 - accuracy: 0.0000e+00
 8/81 [=>............................] - ETA: 0s - loss: 0.2726 - accuracy: 0.0000e+00
16/81 [====>.........................] - ETA: 0s - loss: 0.2329 - accuracy: 0.0000e+00
24/81 [=======>......................] - ETA: 0s - loss: 0.2127 - accuracy: 0.0000e+00
31/81 [==========>...................] - ETA: 0s - loss: 0.2019 - accuracy: 0.0000e+00
38/81 [=============>................] - ETA: 0s - loss: 0.2003 - accuracy: 0.0000e+00
45/81 [===============>..............] - ETA: 0s - loss: 0.1922 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.1865 - accuracy: 0.0000e+00
59/81 [====================>.........] - ETA: 0s - loss: 0.1902 - accuracy: 0.0000e+00
66/81 [=======================>......] - ETA: 0s - loss: 0.1905 - accuracy: 0.0000e+00
73/81 [==========================>...] - ETA: 0s - loss: 0.1989 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.2016 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.2026 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 9ms/step - loss: 0.2026 - accuracy: 0.0000e+00
Epoch 18/20

 1/81 [..............................] - ETA: 0s - loss: 0.3014 - accuracy: 0.0000e+00
 8/81 [=>............................] - ETA: 0s - loss: 0.2769 - accuracy: 0.0000e+00
17/81 [=====>........................] - ETA: 0s - loss: 0.2315 - accuracy: 0.0000e+00
24/81 [=======>......................] - ETA: 0s - loss: 0.2207 - accuracy: 0.0000e+00
32/81 [==========>...................] - ETA: 0s - loss: 0.2170 - accuracy: 0.0000e+00
40/81 [=============>................] - ETA: 0s - loss: 0.2085 - accuracy: 0.0000e+00
48/81 [================>.............] - ETA: 0s - loss: 0.2013 - accuracy: 0.0000e+00
55/81 [===================>..........] - ETA: 0s - loss: 0.1997 - accuracy: 0.0000e+00
62/81 [=====================>........] - ETA: 0s - loss: 0.1998 - accuracy: 0.0000e+00
70/81 [========================>.....] - ETA: 0s - loss: 0.2015 - accuracy: 0.0000e+00
77/81 [===========================>..] - ETA: 0s - loss: 0.2065 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.2083 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 9ms/step - loss: 0.2083 - accuracy: 0.0000e+00
Epoch 19/20

 1/81 [..............................] - ETA: 0s - loss: 0.2798 - accuracy: 0.0000e+00
 8/81 [=>............................] - ETA: 0s - loss: 0.2926 - accuracy: 0.0000e+00
14/81 [====>.........................] - ETA: 0s - loss: 0.2609 - accuracy: 0.0000e+00
22/81 [=======>......................] - ETA: 0s - loss: 0.2353 - accuracy: 0.0000e+00
30/81 [==========>...................] - ETA: 0s - loss: 0.2197 - accuracy: 0.0000e+00
38/81 [=============>................] - ETA: 0s - loss: 0.2185 - accuracy: 0.0000e+00
45/81 [===============>..............] - ETA: 0s - loss: 0.2097 - accuracy: 0.0000e+00
52/81 [==================>...........] - ETA: 0s - loss: 0.2061 - accuracy: 0.0000e+00
59/81 [====================>.........] - ETA: 0s - loss: 0.2102 - accuracy: 0.0000e+00
67/81 [=======================>......] - ETA: 0s - loss: 0.2121 - accuracy: 0.0000e+00
72/81 [=========================>....] - ETA: 0s - loss: 0.2141 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.2127 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.2125 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 9ms/step - loss: 0.2125 - accuracy: 0.0000e+00
Epoch 20/20

 1/81 [..............................] - ETA: 0s - loss: 0.2366 - accuracy: 0.0000e+00
 9/81 [==>...........................] - ETA: 0s - loss: 0.2507 - accuracy: 0.0000e+00
18/81 [=====>........................] - ETA: 0s - loss: 0.2222 - accuracy: 0.0000e+00
26/81 [========>.....................] - ETA: 0s - loss: 0.2045 - accuracy: 0.0000e+00
34/81 [===========>..................] - ETA: 0s - loss: 0.2039 - accuracy: 0.0000e+00
42/81 [==============>...............] - ETA: 0s - loss: 0.1971 - accuracy: 0.0000e+00
50/81 [=================>............] - ETA: 0s - loss: 0.1906 - accuracy: 0.0000e+00
58/81 [====================>.........] - ETA: 0s - loss: 0.1928 - accuracy: 0.0000e+00
66/81 [=======================>......] - ETA: 0s - loss: 0.1959 - accuracy: 0.0000e+00
73/81 [==========================>...] - ETA: 0s - loss: 0.1983 - accuracy: 0.0000e+00
80/81 [============================>.] - ETA: 0s - loss: 0.2029 - accuracy: 0.0000e+00
81/81 [==============================] - 1s 7ms/step - loss: 0.2037 - accuracy: 0.0000e+00

81/81 [==============================] - 1s 8ms/step - loss: 0.2037 - accuracy: 0.0000e+00
lstm_forecast <- lstm_model %>%
    predict(x_pred_arr, batch_size = 1) %>%
    .[, , 1]

1/1 [==============================] - 1s 1s/step

1/1 [==============================] - 1s 1s/step
 
# rescale en format basique
lstm_forecast <- lstm_forecast * scale_factors[2] + scale_factors[1]
lstm_forecast
 [1] 459865.7 464270.5 431565.1 442693.1 455369.7 453950.0
 [7] 473753.8 467633.8 459334.6 482096.4 454499.0 381109.3

X résultats / prédictions par input donc > transforme pour une seule prédiciton

fitted <- predict(lstm_model, x_train_arr, batch_size = 1) %>%
     .[, , 1]

 1/81 [..............................] - ETA: 1s
23/81 [=======>......................] - ETA: 0s
43/81 [==============>...............] - ETA: 0s
65/81 [=======================>......] - ETA: 0s
81/81 [==============================] - 0s 2ms/step

81/81 [==============================] - 0s 2ms/step
if (dim(fitted)[2] > 1) {
    fit <- c(fitted[, 1], fitted[dim(fitted)[1], 2:dim(fitted)[2]])
} else {
    fit <- fitted[, 1]
}

# rescale final de nos données
fitted <- fit * scale_factors[2] + scale_factors[1]
fitted
 [1] 262918.6 264691.5 290889.0 303122.2 314529.3 328454.2
 [7] 288171.8 261282.6 306581.7 288037.8 265662.6 280645.2
[13] 280822.6 272328.9 314008.2 310983.3 326743.0 346064.5
[19] 300931.5 266732.3 320298.7 307821.0 291250.4 302792.3
[25] 324627.1 323489.9 350129.7 344771.4 357006.4 384302.5
[31] 331226.1 291711.0 348780.1 354906.1 322972.3 312396.6
[37] 358186.5 354725.7 399205.4 385704.2 391630.5 408883.1
[43] 361685.7 325749.1 378625.9 378832.8 347489.1 375327.1
[49] 376304.6 377306.2 412887.1 395036.4 383213.9 430576.6
[55] 385044.7 342721.4 408489.9 410726.2 372916.9 392945.1
[61] 393156.0 400025.5 436991.4 431726.2 418205.2 429711.9
[67] 405719.8 356297.2 426671.5 438300.6 392091.9 421278.0
[73] 424864.1 420718.3 455801.7 446976.4 445379.2 464230.2
[79] 425602.3 369791.7 446707.1 449840.2 418900.3 426666.9
[85] 437129.2 443043.2 471919.4 458081.5 466414.5 463707.9
[91] 451208.1 382540.9
fitted <- c(rep(NA, lag), fitted)
fitted
  [1]       NA       NA       NA       NA       NA       NA
  [7]       NA       NA       NA       NA       NA       NA
 [13] 262918.6 264691.5 290889.0 303122.2 314529.3 328454.2
 [19] 288171.8 261282.6 306581.7 288037.8 265662.6 280645.2
 [25] 280822.6 272328.9 314008.2 310983.3 326743.0 346064.5
 [31] 300931.5 266732.3 320298.7 307821.0 291250.4 302792.3
 [37] 324627.1 323489.9 350129.7 344771.4 357006.4 384302.5
 [43] 331226.1 291711.0 348780.1 354906.1 322972.3 312396.6
 [49] 358186.5 354725.7 399205.4 385704.2 391630.5 408883.1
 [55] 361685.7 325749.1 378625.9 378832.8 347489.1 375327.1
 [61] 376304.6 377306.2 412887.1 395036.4 383213.9 430576.6
 [67] 385044.7 342721.4 408489.9 410726.2 372916.9 392945.1
 [73] 393156.0 400025.5 436991.4 431726.2 418205.2 429711.9
 [79] 405719.8 356297.2 426671.5 438300.6 392091.9 421278.0
 [85] 424864.1 420718.3 455801.7 446976.4 445379.2 464230.2
 [91] 425602.3 369791.7 446707.1 449840.2 418900.3 426666.9
 [97] 437129.2 443043.2 471919.4 458081.5 466414.5 463707.9
[103] 451208.1 382540.9
length(fitted)
[1] 104
lstm_forecast <- ts(lstm_forecast,
    start = c(2019, 1),
    end = c(2019, 12),
    frequency = 12
)

lstm_forecast_display <- window(lstm_forecast, start= c(2019,1), end = c(2019,8))

input_ts <- ts(data$y, 
    start = c(2011, 1), 
    end = c(2018, 12), 
    frequency = 12)


lstm_forecast_display
          Jan      Feb      Mar      Apr      May      Jun
2019 459865.7 464270.5 431565.1 442693.1 455369.7 453950.0
          Jul      Aug
2019 473753.8 467633.8
data_ts_test
        Jan    Feb    Mar    Apr    May    Jun    Jul    Aug
2019 443700 441499 480649 463680 453372 505190 445332 370211
plot(input_ts, xlim=c(2011,2020))
#lines(data_ts_test)
lines(lstm_forecast_display, col=3)

NA
NA
NA
LS0tDQp0aXRsZTogfA0KICANCmF1dGhvcjogDQotIENsb3ZpcyBEZWxldHJlDQotIENoYXJsZXMgVml0cnkNCmRhdGU6DQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB0cnVlDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiA3Mg0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmJvZHl7IC8qIE5vcm1hbCAgKi8NCiAgICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgfQ0KdGQgeyAgLyogVGFibGUgICovDQogIGZvbnQtc2l6ZTogOHB4Ow0KfQ0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDU1cHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmgxIHsgLyogSGVhZGVyIDEgKi8NCiAgZm9udC1zaXplOiAzOHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpoMiB7IC8qIEhlYWRlciAyICovDQogICAgZm9udC1zaXplOiAyOHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpoMyB7IC8qIEhlYWRlciAzICovDQogIGZvbnQtc2l6ZTogMzVweDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmNvZGUucnsgLyogQ29kZSBibG9jayAqLw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCnByZSB7IC8qIENvZGUgYmxvY2sgLSBkZXRlcm1pbmVzIGNvZGUgc3BhY2luZyBiZXR3ZWVuIGxpbmVzICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KfQ0KPC9zdHlsZT4NCmBgYA0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQoNCnNvdXJjZSgiRm9uY3Rpb25zLlIiLCBsb2NhbCA9IGtuaXRyOjprbml0X2dsb2JhbCgpKQ0KDQojaW5zdGFsbCBmb3IgZXhwb3J0IGluIHBkZiBmaWxlDQojdGlueXRleDo6aW5zdGFsbF90aW55dGV4KCkNCmBgYA0KDQo8YnI+IDwvYnI+DQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQppZighcmVxdWlyZShmb3JlY2FzdCkpIGluc3RhbGwucGFja2FnZXMoInRtIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpyZXF1aXJlKGZvcmVjYXN0KQ0KDQppZighcmVxdWlyZShmcHAyKSkgaW5zdGFsbC5wYWNrYWdlcygidG0iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCnJlcXVpcmUoZnBwMikNCg0KaWYoIXJlcXVpcmUoTUxtZXRyaWNzKSkgaW5zdGFsbC5wYWNrYWdlcygidG0iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCnJlcXVpcmUoTUxtZXRyaWNzKQ0KDQppZighcmVxdWlyZShnZ3Bsb3QyKSkgaW5zdGFsbC5wYWNrYWdlcygidG0iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCnJlcXVpcmUoZ2dwbG90MikNCg0KaWYoIXJlcXVpcmUoZnBwMikpIGluc3RhbGwucGFja2FnZXMoInRtIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpyZXF1aXJlKGZwcDIpDQoNCmlmKCFyZXF1aXJlKFRTc3R1ZGlvKSkgaW5zdGFsbC5wYWNrYWdlcygidG0iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCnJlcXVpcmUoVFNzdHVkaW8pDQoNCmlmKCFyZXF1aXJlKGdndGhlbWVzKSkgaW5zdGFsbC5wYWNrYWdlcygidG0iLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikNCnJlcXVpcmUoZ2d0aGVtZXMpDQoNCmlmKCFyZXF1aXJlKHRpbWV0aykpIGluc3RhbGwucGFja2FnZXMoInRtIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpyZXF1aXJlKHRpbWV0aykNCg0KDQpgYGANCg0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQppZighcmVxdWlyZShrZXJhcykpIGluc3RhbGwucGFja2FnZXMoInRtIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpyZXF1aXJlKGtlcmFzKQ0KaWYoIXJlcXVpcmUodGVuc29yZmxvdykpIGluc3RhbGwucGFja2FnZXMoInRtIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQpyZXF1aXJlKHRlbnNvcmZsb3cpDQpsaWJyYXJ5KGtlcmFzKQ0KbGlicmFyeSh0ZW5zb3JmbG93KQ0KI2luc3RhbGxfa2VyYXMoKQ0KI2luc3RhbGxfdGVuc29yZmxvdyh2ZXJzaW9uID0gIm5pZ2h0bHkiKQ0KDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KTm91cyBzb3VoYWl0b25zIHLDqWFsaXPDqSBsJyoqw6l0dWRlIGQndW5lIHPDqXJpZSB0ZW1wb3JlbGxlKiogZXQgZmFpcmUgZGVzDQpwcsOpdmlzaW9ucyBzdXIgY2VsbGUtY2kuDQoNCkNldHRlIHPDqXJpZSB0ZW1wb3JlbGxlIGVzdCBsZSB0cmFmaWMgbWVuc3VlbCBkJ3VuZSBDb21wYWduaWUgYcOpcmllbm5lIGRlDQpqYW52aWVyIDIwMTEgw6AgYW/Du3QgMjAxOS4NCg0KTm9zIHByw6l2aXNpb25zIHBvcnRlbnQgc3VyIGxlcyA4IG1vaXMgZGUgbCdhbm7DqWUgMjAxOQ0KDQoNCiMgUmVwcsOpc2VudGF0aW9uIGdyYXBoaXF1ZSBkZSBsYSBzw6lyaWUuDQoNCiMjIEltcG9ydCBkZXMgZG9ubsOpZXMNCg0KSW1wb3J0IGRlIGxhIGJhc2UsIG9uIHPDqWxlY3Rpb25uZSBsYSBjb2xvbm5lIGRlcyB2YWxldXJzDQoNCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmRhdGEgPC0gcmVhZF9kZWxpbSgiVHJhZmljLXZveWFnZXVycy5jc3YiLCANCiAgICBkZWxpbSA9ICI7IiwgbG9jYWxlID0gbG9jYWxlKGVuY29kaW5nID0gIklTTy04ODU5LTEiKSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfdmFsdWUgPC0gZGF0YVssMl0NCnN1bW1hcnkoZGF0YSkNCmBgYA0KDQojIyBDcsOpYXRpb24gZGUgbm90cmUgc8OpcmllIHRlbXBvcmVsbGUNCg0KTm91cyByZXByw6lzZW50b25zIG5vcyBkb25uw6llcyBzb3VzIGZvcm1lIGRlIHPDqXJpZSB0ZW1wb3JlbGxlLg0KDQpVbmUgc8OpcmllIHRlbXBvcmVsbGUgZXN0IHVuIGVuc2VtYmxlIGRlIG3DqXRyaXF1ZSBtw6lzdXLDqWUgc3VyIGRlcyBpbnRlcnZhbGxlcyBkZSB0ZW1wcyByw6lndWxpZXJzLg0KDQpDcsOpYXRpb24gZGUgbGEgc8OpcmllIGNocm9ub2xvZ2lxdWUgYXZlYyBsYSBsaWJyYWlyaWUgVFNzdHVkaW8gOg0KDQotIHN0YXJ0IDogYW5uw6llIGRlIGTDqWJ1dCwNCi0gZnJlcXVlbmN5IDogbmJyIGRlIHZhbGV1ciBwYXIgYW4gPT4gb24gZW4gZnLDqXF1ZW5jZSBtZW5zdWVsbGUgZG9uYyAxMg0KDQpgYGB7cn0NCmxpYnJhcnkoVFNzdHVkaW8pDQpkYXRhX3RzIDwtIHRzKGRhdGFfdmFsdWUsIHN0YXJ0PTIwMTEsIGZyZXF1ZW5jeT0xMikNCnBsb3RfMV9UaW1lU2VyaWVzKGRhdGFfdHMpDQoNCg0KYGBgDQoNCiMjIFPDqXBhcmF0aW9uIGpldSBkZSBkb25uw6llcw0KDQpgYGB7cn0NCiNyZXZvaXIgbCBhZmZpY2hhZ2UgY2FyIGNhIHByZW5kIHBhcyBlbiBjb21wdGUgdHQgMjAxOQ0KZGF0YV90c190cmFpbiA8LSB3aW5kb3coZGF0YV90cywgc3RhcnQgPSBjKDIwMTEsIDEpLCBlbmQgPSBjKDIwMTgsMTIpKQ0KZGF0YV90c190ZXN0IDwtIHdpbmRvdyhkYXRhX3RzLCBzdGFydD0gYygyMDE5LDEpLCBlbmQgPSBjKDIwMTksOCkpDQoNCm5hbWVzKGRhdGEpWzFdIDwtICJkcyINCm5hbWVzKGRhdGEpWzJdIDwtICJ5Ig0KZGF0YV90cmFpbiA8LSBkYXRhWzE6OTYsXQ0KZGF0YV90ZXN0IDwtIGRhdGFbOTc6MTA0LF0NCg0KDQpwbG90KGRhdGFfdHMsIHhsaW09YygyMDExLDIwMjApKQ0KbGluZXMoZGF0YV90c190ZXN0LCBjb2w9MykNCmxlZ2VuZCgidG9wbGVmdCIsIGx0eSA9IDEsIGNvbD1jKDEsMyksIGxlZ2VuZD1jKCJTw6lyaWUgY2hyb25vbG9naXF1ZSBUcmFpbiIsICJTw6lyaWUgY2hyb25vbG9naXF1ZSBUZXN0IikpDQpgYGANCi0+IHN0cm9uZyB0cmVuZCAtPiBwYXRlcm4gcXVpIHNlIHJlcGV0ZSwgc2Fpc29ubmFsaXTDqSA/DQoNCiMjIFJlcHLDqXNlbnRhdGlvbiBkZSBsYSBzYWlzb25uYWxpdMOpDQoNCkFuYWx5c2UgZGUgbGEgc2Fpc29ubmFsaXTDqSBlbiBzdXBlcnBvc2FudCBjaGFxdWUgYW5uw6llIChwYXIgbW9pcyk6DQoNCi0+IGVuIHN1cHByaW1hbnQgbGEgdGVuZGFuY2Ugb24gdm9pdCBiaWVuIGxhIHNhaXNvbm5hbGl0w6kgPT4NCnNhaXNvbm5hbGl0w6kgcsOpZ3VsacOocmUNCg0KDQojIyBBbmFseXNlIGRlIG5vdHJlIHPDqXJpZSB0ZW1wb3JlbGxlDQoNCkNoYXF1ZSBwb2ludCBkZSBub3RyZSBzw6lyaWUgdGVtcG9yZWxsZSBwZXV0IMOqdHJlIGV4cHJpbWVyIGNvbW1lIHVuZSBzb21tZSBvdSB1biBwcm9kdWl0IGRlIDMgY29tcG9zYW50ZXMgOg0KLSBTYWlzb25uYWxpdMOpIChTdCksDQotIFRlbmRhbmNlIChUdCksDQotIEVycmV1ciAoz7V0KSwNCg0KWXQ9U3QrVHQrz7V0IG91IFl0PVN0w5dUdMOXz7V0DQoNCkxhIHN0YXRpb25uYXJpdMOpIGQndW5lIHPDqXJpZSBzaWduaWZpcXVlIHF1ZSBsZSBwcm9jZXNzdXMgcXVpIGfDqW7DqHJlIGxhIHPDqXJpZSBuZSBjaGFuZ2UgcGFzIGRhbnMgbGUgdGVtcHMuIENlbGEgbmUgdmV1dCBwYXMgZGlyZSBxdWUgbGEgc8OpcmllIG5lIGNoYW5nZSBwYXMgZGFucyBsZSB0ZW1wcywgbWFpcyBxdWUgbGEgZmHDp29uIGRvbnQgZWxsZSBjaGFuZ2UsIG4nZXN0IHBhcyBtb2RpZmnDqSBkYW5zIGxlIHRlbXBzLiANCg0KVGVzdG9ucyBzaSBsYSBzw6lyaWUgZXN0IHN0YXRpb25uYWlyZSA6IA0KDQpgYGB7cn0NCmxpYnJhcnkodHNlcmllcykNCmFkZi50ZXN0KGRhdGFfdHMpICNwLXZhbHVlIDwwLjUgPT4gc3RhdGlvbm5haXJlDQprcHNzLnRlc3QoZGF0YV90cykNCg0KYGBgDQpEb25jIG5vdHJlIHPDqXJpZSBlc3QgYmllbiBzdGF0aW9ubmFpcmUgZXQgcGV1dCDDqnRyZSDDqXR1ZGnDqWUgZmFjaWxlbWVudC4NCmBgYHtyfQ0KZ2dzZWFzb25wbG90KGRhdGFfdHMpDQpkYXRhX3RzX3dpdGhvdXRfdHJlbmQgPSBkaWZmKGRhdGFfdHMpDQpnZ3NlYXNvbnBsb3QoZGF0YV90c193aXRob3V0X3RyZW5kKQ0KYGBgDQoNCiMjIFJlcHLDqXNlbnRhdGlvbiBkZXMgZMOpY29tcG9zaXRpb25zIHBvc3NpYmxlcw0KDQpERUNPTVBPU0lUSU9OIDogYWRkaXRpdmUgLyBNdWx0aXBsaWNhdGl2ZSBUcyA9IFRyZW5kICsgU2Vhc29uYWwgKyBSYW5kb20NCi8gVHMgPSBUcmVuZCBcKiBTZWFzb25hbCBcKiBSYW5kb20NCg0KYGBge3J9DQpkZWNvbXBvc2VkX2RhdGEgPC0gZGVjb21wb3NlKGRhdGFfdHNfdHJhaW4sIHR5cGU9ImFkZGl0aXZlIikNCnBsb3QoZGVjb21wb3NlZF9kYXRhJHRyZW5kKQ0KcGxvdChkZWNvbXBvc2VkX2RhdGEkc2Vhc29uYWwpDQpwbG90KGRlY29tcG9zZWRfZGF0YSRyYW5kb20pDQoNCmJveHBsb3QoZGF0YV90cyB+IGN5Y2xlKGRhdGFfdHMpKQ0KYGBgDQoNCi0+IG9uIGRpc3Rpbmd1ZSBkZXMgc2Fpc29ubmFsaXTDqXMgPT4gZmFpcmUgcsOpZ3Jlc3Npb24gY2EgbidhIHBhcyBkZSBzZW5zDQo9PiBtb2TDqGxlIGRlIEJ1eXMgQmFsbG90DQoNCi0+IGJvbm5lIHJlcGFydGl0aW9uIGR1IGJydWl0IC0+IHF1ZWxxdWVzIG91dGxpZXJzDQoNCmBgYHtyfQ0KY2hlY2tyZXNpZHVhbHMocmVtYWluZGVyKGRlY29tcG9zZWRfZGF0YSkpDQpgYGANCg0KT24gYSB0ZW5kYW5jZXMgKyBzYWlzb25uYWxpdMOpDQoNCiMgTW9kw6hsZXMgZXNwYWNlLcOpdGF0DQoNCi0gICBtZWFuZiA6IEF2ZXJhZ2UgTWV0aG9kIDogcHJlbmQgbGEgdmFsZXVyIG1veWVubmUgZGUgdG91dGUgbGVzDQogICAgb2JzZXJ2YXRpb25zIHBvdXIgdG91dGVzIGxlcyBwcsOpZGljdGlvbnMsDQotICAgbmFpdmUgOiBOYWl2ZSBNZXRob2QgOiBwcmVuZCBsYSBkZXJuacOocmUgb2JzZXJ2YXRpb24gcG91ciB0b3V0ZXMgbGVzDQogICAgcHLDqWRpY3Rpb25zLA0KLSAgIGRyaWZ0IDogRHJpZnQgTWV0aG9kIDogcHJlbmQgbGEgcHJlbWnDqHJlIGV0IGxhIGRlcm5pw6hyZSBvYnNlcnZhdGlvbnMNCiAgICBldCB0cmFjZSB1bmUgbGlnbmVzIGVudHJlIGxlcyBkZXV4LCBvbiB1dGlsaXNlIGxhIGNvdXJiZSBwb3VyIGxlcw0KICAgIHByw6lkaWN0aW9ucywNCi0gICBzbmFpdmUgOiBTZWFzb25hbCBOYWl2ZSBGb3JlY2FzdCA6IFByZW5kIGxhIGRlcm5pw6hyZSB2YWxldXIgZGUgbGENCiAgICBzYWlzb24gcHLDqWPDqWRlbnRlIGNvbW1lIHByw6lkaWN0aW9uIChleCA6IHNlcHQgMjAxOCA9IHNlcCAyMDE5ICsNCiAgICBlcnJldXIpDQoNCmBgYHtyfQ0KbGlicmFyeShmb3JlY2FzdCkNCm1lYW4gPC0gbWVhbmYoZGF0YV90c190cmFpbiwgaD04KQ0KbmFpdmVtIDwtIG5haXZlKGRhdGFfdHNfdHJhaW4sIGg9OCkNCmRyaWZ0bSA8LSByd2YoZGF0YV90c190cmFpbiwgaD04LCBkcmlmPVQpDQpzbmFpdmVtIDwtIHNuYWl2ZShkYXRhX3RzX3RyYWluLCBoPTgpDQpgYGANCg0KYGBge3J9DQpwbG90KG1lYW4sIHBsb3QuY29uZiA9IEYsIG1haW49IiIpDQpsaW5lcyhuYWl2ZW0kbWVhbiwgY29sPTIsIGx0eT0xKQ0KbGluZXMoZHJpZnRtJG1lYW4sIGNvbD01LCBsdHk9MSkNCmxpbmVzKHNuYWl2ZW0kbWVhbiwgY29sID0gNCwgbHR5PTEpDQpsZWdlbmQoInRvcGxlZnQiLCBsdHk9MSwgY29sPWMoMSwyLDMsNCksIGxlZ2VuZD1jKCJNZWFuIE1ldGhvZCIsICJOYWl2ZSBNZXRob2QiLCAiRHJpZiBNZXRob2QiLCAiU2Vhc29uYWwgTmFpdmUiKSkNCg0KDQojY29tcGFyYWlzb24gOg0KcGxvdChzbmFpdmVtLCBwbG90LmNvbmYgPSBGLCBtYWluPSIiKQ0KbGluZXMoZGF0YV90c190ZXN0LCBjb2wgPSA2LCBsdHk9MSwgbHdkPTMpDQoNCnBsb3QoZHJpZnRtLCBwbG90LmNvbmYgPSBGLCBtYWluPSIiKQ0KbGluZXMoZGF0YV90c190ZXN0LCBjb2wgPSA2LCBsdHk9MSwgbHdkPTMpDQoNCmBgYA0KDQpPbiByZWdhcmRlIDogTUFFIDogTWVhbiBBYnNvbHV0ZSBFcnJvciA6IFJNU0UgOiBSb290IE1lYW4gU3F1YXJyZWQgRXJyb3INCg0KOiAgIE1BU0UgOiBNZWFuIEFic29sdXRlIFNjYWxlZCBFcnJvciA6IE1BUEUgOiBNZWFuIEFic29sdXRlIFBlcmNlbnRhZ2UNCiAgICBFcnJvciA6DQoNCnJlcyA9IHByZWQgLSB2YWwgTUFFID0gc3VtKGFicyhyZXMpKS9sZW5ndGgodmFsKSBSU1MgPSBzdW0ocmVzXF4yKSBNU0UgPQ0KUlNTL2xlbmd0aCh2YWwpIFJNU0UgPSBzcXJ0KE1TRSkNCg0KTGEgcGx1cyBwb3B1bGFpcmUgZXN0IGxhIE1BUEUNCg0KTUFQRSh5X3ByZWQsIHlfdHJ1ZSkNCg0KXCRNQVBFID0gKDEvbikgXCogzqMoXHxhY3R1YWwgLS0gZm9yZWNhc3RcfCAvIFx8YWN0dTBhbFx8KSBcKiAxMA0KDQoiYSBNQVBFIHZhbHVlIG9mIDYlIG1lYW5zIHRoYXQgdGhlIGF2ZXJhZ2UgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZQ0KZm9yZWNhc3RlZCB2YWx1ZSBhbmQgdGhlIGFjdHVhbCB2YWx1ZSBpcyA2JSINCg0KYGBge3J9DQpwcmludChzdW1tYXJ5KG1lYW4pKQ0KY2hlY2tyZXNpZHVhbHMobWVhbikNCmFjY3VyYWN5KG1lYW4sIGRhdGFfdHNfdGVzdCkNCg0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQoc3VtbWFyeShuYWl2ZW0pKQ0KY2hlY2tyZXNpZHVhbHMobmFpdmVtKQ0KYWNjdXJhY3kobmFpdmVtLCBkYXRhX3RzX3Rlc3QpDQoNCmBgYA0KDQpgYGB7cn0NCnByaW50KHN1bW1hcnkoZHJpZnRtKSkNCmNoZWNrcmVzaWR1YWxzKGRyaWZ0bSkNCmFjY3VyYWN5KGRyaWZ0bSwgZGF0YV90c190ZXN0KQ0KDQpgYGANCg0KYGBge3J9DQpwcmludChzdW1tYXJ5KHNuYWl2ZW0pKQ0KY2hlY2tyZXNpZHVhbHMoc25haXZlbSkNCmFjY3VyYWN5KHNuYWl2ZW0sIGRhdGFfdHNfdGVzdCkNCg0KYGBgDQoNCiMgRXR1ZGUgZHUgTW9kw6hsZSBkZSBCdXlzLUJhbGxvdA0KDQojIyBNb2TDqGxlDQoNCjxodHRwczovL21wcmEudWIudW5pLW11ZW5jaGVuLmRlLzc3NzE4LzEvTVBSQV9wYXBlcl83NzcxOC5wZGY+IHBhZ2UgMTc1DQoNCkwnYXBwcm9jaGUgZGUgQlVZUy1CQUxMT1QgY29uc2lzdGUgw6AgaW50cm9kdWlyZSBkZXMgdmFyaWFibGVzDQppbmRpY2F0cmljZXMgY29ycmVzcG9uZGFudCDDoCBjaGFxdWUgc2Fpc29uIGTDqWZpbml0IHBhciBsZSBjeWNsZQ0KZCdvYnNlcnZhdGlvbi4gUG91ciBsZXMgZG9ubsOpZXMgdHJpbWVzdHJpZWxsZXMsIG9uIGludMOoZ3JlIDQgdmFyaWFibGVzDQppbmRpY2F0cmljZXMuIEV0IHBvdXIgbGVzIGRvbm7DqWVzIG1lbnN1ZWxsZXMsIG9uIGludMOoZ3JlIDEyIHZhcmlhYmxlcw0KaW5kaWNhdHJpY2VzLg0KDQpMZSBtb2TDqGxlIGRvaXQgYWxvcnMgw6p0cmUgZXN0aW3DqSAoc2FucyBjb25zdGFudGUpIGF2ZWMgY2VzIHZhcmlhYmxlcw0KaW5kaWNhdHJpY2VzLg0KDQojIyBQcsOpZGljdGlvbiBkZXMgdmFsZXVycyBkZSAyMDE5DQoNClByw6lwYXJhdGlvbiBkZXMgZG9ubsOpZXMuDQoNCmBgYHtyfQ0KQW5uZWVzPWFzLm51bWVyaWModGltZShkYXRhX3RzX3RyYWluKSkNCnRzX0RhdGFGcmFtZSA9ZGF0YS5mcmFtZSh0cmFmaWM9ZGF0YV90c190cmFpbixYPWFzLm51bWVyaWMoQW5uZWVzKSkNCmBgYA0KDQpDcsOpYXRpb24gZHUgbW9kw6hsZQ0KDQpgYGB7cn0NClJlZ3Jlc3Npb24gPC0gbG0odHJhZmljflgsZGF0YSA9IHRzX0RhdGFGcmFtZSkNCmBgYA0KDQokWHQgPSBadCArIFN0ICsgXG11IHQkDQoNCkxhIHRlbmRhbmNlIFByw6lkaWN0aW9uIHN1ciBsZXMgZG9ubsOpZXMgZnV0dXJzLg0KDQpgYGB7cn0NCnRlbmRhbmNlPXByZWRpY3QoUmVncmVzc2lvbikNCg0KQW5uZWVNb2lzTnVtZXJpY0Z1dHVyPXNlcShtYXgoQW5uZWVzKSsxLzEyLGxlbmd0aD04LGJ5PTEvMTIpICAjbGVzIDEwIHByb2NoYWlucyBtb2lzDQoNCnRlbmRhbmNlMj1wcmVkaWN0KFJlZ3Jlc3Npb24sIG5ld2RhdGE9ZGF0YS5mcmFtZShYPUFubmVlTW9pc051bWVyaWNGdXR1cikpIA0KYGBgDQoNCmBgYHtyfQ0KdHNfRGF0YUZyYW1lJHRyYWZpY19yZXNpZHVhbCA8LSByZXNpZHVhbHMoUmVncmVzc2lvbikNCmBgYA0KDQpEw6lmaW5pc3NvbnMgbGUgbW9pcw0KDQpgYGB7cn0NCnRzX0RhdGFGcmFtZSRtb2lzIDwtIHJvdW5kKHRzX0RhdGFGcmFtZSRYIC0gdHJ1bmModHNfRGF0YUZyYW1lJFgpLGRpZ2l0PTQpDQpgYGANCg0KQ3LDqWF0aW9uIGR1IDJuZCBtb2TDqGxlIGF2ZWMgbGVzIG1vaXMNCg0KYGBge3J9DQpSZWdyZXNzaW9uMiA9bG0odHJhZmljX3Jlc2lkdWFsfjArYXMuZmFjdG9yKG1vaXMpLGRhdGE9dHNfRGF0YUZyYW1lKQ0KYGBgDQoNClByw6lkaWN0aW9uIGRlIGxhIHNhaXNvbm5hbGl0w6kNCg0KYGBge3J9DQpwcmVkaWN0aW9uMiA9cHJlZGljdChSZWdyZXNzaW9uMikNCmBgYA0KDQpQcsOpZGljdGlvbiBzdXIgbGVzIG1vaXMNCg0KYGBge3J9DQpNb2lzTnVtZXJpYz0gcm91bmQoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyIC0gdHJ1bmMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyDQogICAgICAgICAgICAgICAgICAgICApLDQpDQpQcmVkaWN0aW9uMyA9cHJlZGljdCggUmVncmVzc2lvbjIsIG5ld2RhdGE9IGRhdGEuZnJhbWUobW9pcz1Nb2lzTnVtZXJpYykpDQoNCmBgYA0KDQpDYWxjdWxvbnMgdW5lIHLDqWdpb24gZGUgY29uZmlhbmNlIGF2ZWMgbCdlcnJldXIgZCdhanVzdGVtZW50DQoNCmBgYHtyfQ0KUmVzaWR1c1JlZ3Jlc3Npb24yPXJlc2lkdWFscyhSZWdyZXNzaW9uMikNCmhpc3QoUmVzaWR1c1JlZ3Jlc3Npb24yKQ0KMS45NipzcXJ0KHZhcihSZXNpZHVzUmVncmVzc2lvbjIpKQ0KYGBgDQoNCiMjIEF1dG8gY29ycsOpbGF0aW9uIGRlIGxhIHPDqXJpZSB0ZW1wb3JlbGxlDQoNCkwnYXV0b2NvcnLDqWxhdGlvbiBkZSBub3RyZSBzw6lyaWUgdGVtcG9yZWxsZSBjb3JyZXNwb25kIMOgIGxhIGNvcnLDqWxhdGlvbg0KZW50cmUgdW5lIG1lc3VyZSBkdSB0cmFmaWMgJHQkIGV0IGxlcyBtZXN1cmVzIHByw6ljw6lkZW50ZXMgJHQgLSBrJCBvdSBsZXMNCm1lc3VyZXMgc3VpdmFudGVzICR0ICsgayQuDQoNCkwnYXV0byBjb3ZhcmlhbmNlIGQndW5lIHZhcmlhYmxlICRYdCQgZGUgbW95ZW5uZSAkXG11JCBldCBkJ8OpY2FydCB0eXBlDQokXHNpZ21hJCDDoCB1biBkw6ljYWxhZ2UgJGskIGVzdCBkb25uw6kgcGFyIGxhIGZvcm11bGUNCg0KJFxnYW1tYV9rPSBFKChYX3QtXG11KShYX3t0K2t9LVxtdSkpJA0KDQpPbiBlbiBkw6lkdWl0IGwnYXV0b2NvcnLDqWxhdGlvbiBjb3JyZXNwb25kYW50ZSA6DQoNCiRccmhvX2s9XGZyYWN7XGdhbW1hX2t9e1xzaWdtYV4yfSQNCg0KQWZmaWNob25zIGxlcyBhdXRvY29ycsOpbGF0aW9ucyBkZSBsYSBzw6lyaWVzIGdyw6JjZSDDoCB1biBjb3Jyw6lsb2dyYW1tZQ0KDQpgYGB7cn0NCkFDRl9TdXJfVmFsZXVyc19QcmVkaXRlcyA8LSBhY2YocHJlZGljdGlvbjIpDQpgYGANCg0KSWwgZXN0IG5vcm1hbCBxdWUgbGEgc8OpcmllIHNvaXQgYXV0b2NvcnLDqWzDqSB0b3RhbGVtZW50IMOgIGVsbGUgYXZlYyB1bg0KZMOpY2FsYWdlIG51bGxlLg0KDQpPbiBvYnNlcnZlIHVuZSBjb3Jyw6lsYXRpb24gZm9ydGUgKDAuODcpIGF2ZWMgdW4gZMOpY2FsYWdlIChsYWcpIGRlIDEyLA0KY2VsYSBjb3JyZXNwb25kIGJpZW4gw6AgdW5lIHNhaXNvbm5hbGl0w6kgYW5udWVsbGUuDQoNCmBgYHtyfQ0KcHJpbnQoZGF0YS5mcmFtZShBQ0ZfU3VyX1ZhbGV1cnNfUHJlZGl0ZXMkbGFnLEFDRl9TdXJfVmFsZXVyc19QcmVkaXRlcyRhY2YpWzE6MTMsXSkNCmBgYA0KDQpSZWNhbGN1bG9ucyBsYSB2YWxldXIgZCdhdXRvLWNvcnLDqWxhdGlvbiBvYnRlbnUgZW4gYXBwbGlxdWFudCBsYQ0KZm9ybXVsZS4NCg0KT2JzZXJ2b25zIGwnYXBwbGljYXRpb24gZGUgbGEgZm9ybXVsZSwgZW4gY2hvaXNpc3NhbnQgdW4gZMOpY2FsYWdlIGRlIDEyDQoNCmBgYHtyfQ0KI0NvbnN0YW50ZXMNCk5vbWJyZV9PYnNlcnZhdGlvbnM9OTYNCmRlY2FsYWdlPTEyDQoNCiNFc3RpbWF0aW9ucw0KbW95ZW5uZU11PW1lYW4ocHJlZGljdGlvbjIpDQpzZFNpZ21hPXNkKHByZWRpY3Rpb24yKQ0KDQoNClNlcmllMT1wcmVkaWN0aW9uMlsoZGVjYWxhZ2UrMSk6IDk2ICAgXQ0KU2VyaWUyPXByZWRpY3Rpb24yWyAgIDEgOig5Ni1kZWNhbGFnZSldDQoNCkdhbW1hRGVjYWxhZ2UxMj1tZWFuKChTZXJpZTEtbW95ZW5uZU11KSooU2VyaWUyLW1veWVubmVNdSkpKigoTm9tYnJlX09ic2VydmF0aW9ucy1kZWNhbGFnZSkvKE5vbWJyZV9PYnNlcnZhdGlvbnMpKQ0KDQpSaG9EZWNhbGFnZTEyPUdhbW1hRGVjYWxhZ2UxMi8oc2RTaWdtYV4yKQ0KUmhvRGVjYWxhZ2UxMg0KYGBgDQoNCg0KDQpMZSByw6lzdWx0YXQgb2J0ZW51IGVzdCBjb3JyZWN0LiBMJ2F1dG8gY29ycsOpbGF0aW9uIGF2ZWMgdW4gZMOpY2FsYWdlIGRlIDEyIGVzdCBkb25jIHRyw6hzIGZvcnRlLg0KDQpEZSBwbHVzIGNldHRlIGF1dG8gY29ycsOpbGF0aW9uIMOpdGFudCBwb3NpdGl2ZSwgY2VsYSBpbmRpcXVlIHVuZSB0ZW5kYW5jZSBjcm9pc3NhbnRlLg0KDQoNCg0KbGEgZGV1eGnDqG1lIHBsdXMgZm9ydGUgY29ycsOpbGF0aW9uIGVzdCBvYnNlcnPDqSBhdmVjIHVuIGTDqWNhbGFnZSBkZSA1LA0Kb2JzZXJ2b25zIGNlbGEgZ3JhcGhpcXVlbWVudA0KDQpgYGB7cn0NCnBsb3QgICggMTpsZW5ndGgocHJlZGljdGlvbjIpLCAgIHByZWRpY3Rpb24yLHR5cGU9ImwiKQ0KcG9pbnRzKCgxOmxlbmd0aChwcmVkaWN0aW9uMikpLTUscHJlZGljdGlvbjIsdHlwZT0ibCIsY29sPSJyZWQiKQ0KYGBgDQoNCkNldHRlIGNvcnLDqWxhdGlvbiBlc3QgcGV1IHBlcnRpbmVudGUuDQoNCmBgYHtyfQ0KcHJpbnQoZGF0YS5mcmFtZShBQ0ZfU3VyX1ZhbGV1cnNfUHJlZGl0ZXMkbGFnLEFDRl9TdXJfVmFsZXVyc19QcmVkaXRlcyRhY2YpWzE6MTMsXSkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQpBcHLDqHMgYXZvaXIgw6l0dWRpZXIgbGVzIGF1dG8tY29ycsOpbGF0aW9ucyBzdXIgbCdlbnNlbWJsZSBkdSBtb2TDqGxlLA0KT2JzZXJ2b25zIGxlcyBhdXRvLWNvcnLDqWxhdGlvbnMgc3VyIGxlcyByw6lzaWR1cyBkdSBtb2TDqGxlIGRlDQpCdXlzLUJhbGxvdC4NCg0KLSAgIFRleHRlIHBvdXIgZGlyZSBxdWUgbGVzIGFjY2lkZW50cyBuZSBkb2l2ZW50IHBhcyDDqnRyZSBjb3Jyw6lsw6lzIFwqDQoNCmBgYHtyfQ0KcGxvdChhY2YoUmVzaWR1c1JlZ3Jlc3Npb24yKSkNCmBgYA0KDQpQb3VyIG5vdHJlIG1vZMOobGUsIGlsIG4neSBhIGF1Y3VuZSBhdXRvLWNvcnLDqWxhdGlvbiBzaWduaWZpY2F0aXZlLg0KKHN5bWJvbGlzw6kgcGFyIGxhIGxpZ25lIGJsZXUpDQoNCiMjIENvbXBhcmFpc29uIGRlcyBwcsOpZGljdGlvbnMgZXQgZGVzIHZhbGV1cnMgcsOpZWxsZXMNCg0KQWZmaWNoYWdlIGRlIGxhIHRlbmRhbmNlDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpCdXlzX2JhbGxvdF9wbG90X3RlbmRhbmNlIDwtIHBsb3QoZGF0YV90cywNCiAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIkFwcGxpY2F0aW9uIGR1IG1vZMOobGUgZGUgQnV5c19CYWxsb3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQW5uw6llcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJOb21icmUgZGUgVm95YWdldXJzIikgDQoNCiNkcm9pdGUgZGUgdGVuZGFuY2UNCmxpbmVzKEFubmVlcyx0ZW5kYW5jZSxjb2w9ImJsdWUiLGx3ZD0yKSAgDQoNCiNwcsOpZGljdGlvbiBkZSBsYSB0ZW5kYW5jZSBmdXR1cg0KbGluZXMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyLHRlbmRhbmNlMixjb2w9InJlZCIpDQoNCg0KYGBgDQoNCkFmZmljaGFnZSBkdSBtb2TDqGxlIGRlIEJ1eXMgQmFsbG90DQoNCmBgYHtyfQ0KDQpCdXlzX2JhbGxvdF9wbG90IDwtIHBsb3QoZGF0YV90cywNCiAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIkFwcGxpY2F0aW9uIGR1IG1vZMOobGUgZGUgQnV5c19CYWxsb3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQW5uw6llcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJOb21icmUgZGUgVm95YWdldXJzIikgDQoNCg0KDQojcHLDqWRpY3Rpb24gZHUgbW9kw6hsZSBkZSBCdXlzIGJhbGxvdA0KbGluZXMoQW5uZWVzLHRlbmRhbmNlK3ByZWRpY3Rpb24yLGNvbD0iYmx1ZSIsbHdkPTIpDQoNCiNJbnRlcnZhbCBkZSBjb25maWFuY2UNCiBwb2x5Z29uKGMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyLHJldihBbm5lZU1vaXNOdW1lcmljRnV0dXIpKSwNCiBjKHRlbmRhbmNlMitQcmVkaWN0aW9uMy0xLjk2KnNxcnQodmFyKFJlc2lkdXNSZWdyZXNzaW9uMikpLA0KIHJldih0ZW5kYW5jZTIrUHJlZGljdGlvbjMrMS45NipzcXJ0KHZhcihSZXNpZHVzUmVncmVzc2lvbjIpKSkpLA0KIGNvbD0iY2FkZXRibHVlMSIsYm9yZGVyPU5BKQ0KIA0KICNQcmVkaWN0aW9uIGRlcyB2YWxldXJzDQogbGluZXMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyLHRlbmRhbmNlMitQcmVkaWN0aW9uMyxjb2w9ImJsdWUiLGx3ZD0yKQ0KIA0KIA0KIGxpbmVzKGRhdGFfdHNfdGVzdCxjb2w9ImJsYWNrIixsd2Q9MykNCmBgYA0KDQpBZmZpY2hhZ2UgZGUgbGEgcHLDqWRpY3Rpb24gc3VyIGxlcyA4IG1vaXMgZGUgMjAyMA0KDQpgYGB7cn0NCg0KQnV5c19iYWxsb3RfcGxvdCA8LSBwbG90KGRhdGFfdHNfdGVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIkFwcGxpY2F0aW9uIGR1IG1vZMOobGUgZGUgQnV5c19CYWxsb3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQW5uw6llcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgeWxhYiA9ICJOb21icmUgZGUgVm95YWdldXJzIikgDQoNCg0KDQojcHLDqWRpY3Rpb24gZHUgbW9kw6hsZSBkZSBCdXlzIGJhbGxvdA0KbGluZXMoQW5uZWVzLHRlbmRhbmNlK3ByZWRpY3Rpb24yLGNvbD0iYmx1ZSIsbHdkPTIpDQoNCiNJbnRlcnZhbCBkZSBjb25maWFuY2UNCiBwb2x5Z29uKGMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyLHJldihBbm5lZU1vaXNOdW1lcmljRnV0dXIpKSwNCiBjKHRlbmRhbmNlMitQcmVkaWN0aW9uMy0xLjk2KnNxcnQodmFyKFJlc2lkdXNSZWdyZXNzaW9uMikpLA0KIHJldih0ZW5kYW5jZTIrUHJlZGljdGlvbjMrMS45NipzcXJ0KHZhcihSZXNpZHVzUmVncmVzc2lvbjIpKSkpLA0KIGNvbD0iY2FkZXRibHVlMSIsYm9yZGVyPU5BKQ0KIA0KICNQcmVkaWN0aW9uIGRlcyB2YWxldXJzDQogbGluZXMoQW5uZWVNb2lzTnVtZXJpY0Z1dHVyLHRlbmRhbmNlMitQcmVkaWN0aW9uMyxjb2w9ImJsdWUiLGx3ZD0yKQ0KIA0KIA0KIGxpbmVzKGRhdGFfdHNfdGVzdCxjb2w9ImJsYWNrIixsd2Q9MykNCmBgYA0KDQpQcsOpcGFyYXRpb24gRGF0YUZyYW1lIHBvdXIgYWZmaWNoYWdlIGdncGxvdA0KDQpgYGB7cn0NCkRhdGFBZmZpY2hhZ2VHR3Bsb3QgPSBhcy5kYXRhLmZyYW1lKGRhdGFfdHMpDQpEYXRhQWZmaWNoYWdlR0dwbG90JEFubmVlcyA9IGMoQW5uZWVzLCBBbm5lZU1vaXNOdW1lcmljRnV0dXIpDQpEYXRhQWZmaWNoYWdlR0dwbG90JEFubmVlc1JvdW5kID0gcm91bmQoRGF0YUFmZmljaGFnZUdHcGxvdCRBbm5lZXMpDQpEYXRhQWZmaWNoYWdlR0dwbG90JFByZWRpY3Rpb25UZW5kYW5jZSA9IGModGVuZGFuY2UgLHRlbmRhbmNlMikNCkRhdGFBZmZpY2hhZ2VHR3Bsb3QkQnV5c0JhbG90TW9kZWxlID0gYyh0ZW5kYW5jZStwcmVkaWN0aW9uMix0ZW5kYW5jZTIrUHJlZGljdGlvbjMgKQ0KDQoNCmBgYA0KDQpSZXByb2R1aXNvbnMgbGVzIGdyYXBoaXF1ZXMgYXZlYyBnZ3Bsb3QyIHBvdXIgdW4gcsOpc3VsdGF0IHBsdXMNCnByb2Zlc3NzaW9ubmVsLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3RoZW1lcykNCg0KcCA8LSBnZ3Bsb3QoZGF0YSA9RGF0YUFmZmljaGFnZUdHcGxvdCwgYWVzKHggPSBBbm5lZXMpICkgKyANCg0KICBnZW9tX2xpbmUoYWVzKHkgPSB0cmFmaWMgKSwgc2l6ZSA9IDAuOSwgYWxwaGEgPSAwLjcpKw0KDQogICNnZW9tX2xpbmUoYWVzKHkgPSBQcmVkaWN0aW9uVGVuZGFuY2UpLCBzaXplID0gMC42LCBhbHBoYSA9IDAuODUsbGluZXR5cGU9InR3b2Rhc2giICkrDQogIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBCdXlzQmFsb3RNb2RlbGUpLCBzaXplID0gMS4yLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiYmx1ZSIpKw0KICBsYWJzKHRpdGxlID0gIkFwcGxpY2F0aW9uIGR1IG1vZMOobGUgZGUgQnV5c19CYWxsb3QiLA0KICAgICAgIHg9IkFubsOpZXMiLA0KICAgICAgICAgeT0gIk5vbWJyZSBkZSBWb3lhZ2V1cnMiKSsNCnRoZW1lX2ZpdmV0aGlydHllaWdodCgpKw0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KCksIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlJ1YmlrIikpIA0KDQojc3VyIGwnYW5uw6llIDIwMTkNCnAyIDwtIGdncGxvdChkYXRhID1EYXRhQWZmaWNoYWdlR0dwbG90LCBhZXMoeCA9IEFubmVlcykgKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSB0cmFmaWMgKSwgc2l6ZSA9IDEuMiwgYWxwaGEgPSAwLjcpKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBCdXlzQmFsb3RNb2RlbGUpLCBzaXplID0gMS40LCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiYmx1ZSIpKw0KdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkrDQogICB4bGltICgyMDE5LjAsIDIwMTkuNTgzKSArDQogIHlsaW0gKDQzNTAwMCwgNTIwMDAwKSANCg0KDQojQWpvdXQgem9vbSBzdXIgMjAxOQ0KcCArIA0KICBhbm5vdGF0aW9uX2N1c3RvbShnZ3Bsb3RHcm9iKHAyKSwgeG1pbiA9IDIwMTUsIHhtYXggPSAyMDIwLCB5bWluID0gNTAwMDAsIHltYXggPSAyODAwMDApICsNCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0gMjAxNSwgeG1heCA9IDIwMjAsIHltaW4gPSA1MDAwMCwgeW1heCA9IDI4MDAwMCksIGNvbG9yPSdibGFjaycsIGxpbmV0eXBlPSdkYXNoZWQnLCBhbHBoYT0wKSANCg0KDQoNCmBgYA0KDQpOb3VzIGF2b25zIHLDqXVzc2kgw6AgYWp1c3RlciB1bmUgZHJvaXRlIGRlIHLDqWdyZXNzaW9uLiBvbiByZW1hcnF1ZSBxdWUgbGENCnByw6lkaWN0aW9uIHNlbWJsZSBiaWVuIGNvcnJlc3BvbmRyZSDDoCBsYSByw6lhbGl0w6kgc2kgb24gZmFpdCBhYnN0cmFjdGlvbg0KZHUgZGVybmllciBtb2lzIG/DuSBsZSBub21icmUgZGUgdm95YWdldXJzIGEgYmllbiBwbHVzIGNodXTDqSBxdWUgbGENCnByw6lkaWN0aW9uIGR1IG1vZMOobGUgZGUgQnV5cy1CYWxvdC4NCg0KQ29tcGFyb25zIGF2ZWMgdW4gYWp1c3RlbWVudCBsb2NhbCByw6lhbGlzw6kgcGFyIGxpc3NhZ2UgbW95ZW5uZXMgbW9iaWxlcy4NCg0KIyMgQ29tcGFyYWlzb24gYXZlYyBsZXMgdmFsZXVycyBvYnNlcnbDqWVzDQoNCiMgTGlzc2FnZSBtb3llbm5lIG1vYmlsZQ0KDQojIyBEw6lmaW5pdGlvbg0KDQpNZXR0cmUgYmVsbGUgZm9ybXVsZSBlbiBsYXRleCBpY2kNCg0KIyMgQ2hvaXggTW95ZW5uZSBtb2JpbGVzDQoNCiMjIENvbnNlcnZhdGlvbiAmIEFubnVsYXRpb24NCg0KDQoNCg0KDQoNCiMgTGlzc2FnZSBleHBvbmVudGllbGxlDQoNCiMjIExpc3NhZ2Ugc2ltcGxlDQoNCmBgYHtyfQ0KZmNzdF9zZSA8LSBzZXMoZGF0YV90c190cmFpbiwgaCA9IDgpDQpwcmludChzdW1tYXJ5KGZjc3Rfc2UpKQ0KY2hlY2tyZXNpZHVhbHMoZmNzdF9zZSkNCmBgYA0KDQpgYGB7cn0NCnBsb3QoZmNzdF9zZSkNCmxpbmVzKGRhdGFfdHNfdGVzdCwgY29sPSJyZWQiKQ0KDQoNCmRmX3NlID0gYXMuZGF0YS5mcmFtZShmY3N0X3NlKQ0KcHJlZGljdF92YWx1ZV9zZSA8LSBkZl9zZSRgUG9pbnQgRm9yZWNhc3RgDQpNQVBFKHByZWRpY3RfdmFsdWVfc2UsIGRhdGFfdHNfdGVzdCkqMTAwDQpgYGANCg0KIyMgT3B0aW1pc2F0aW9uIGR1IG1vZMOobGUNCg0KRml0IEV4cG9uZW50aWFsIFNtb290aGluZyBtb2RlbCAtPiB0cm91dmUgbGUgbWVpbGxldXIgbGlzc2FnZSBleHBvDQoNCmBgYHtyfQ0KZml0X2V0cyA8LSBldHMoZGF0YV90c190cmFpbikgDQpwcmludChzdW1tYXJ5KGZpdF9ldHMpKQ0KY2hlY2tyZXNpZHVhbHMoZml0X2V0cykNCg0KDQpgYGANCg0KYGBge3J9DQpmY3N0X2V0cyA8LSBmb3JlY2FzdChmaXRfZXRzLCBoPTgpDQpwbG90KGZjc3RfZXRzKQ0KbGluZXMoZGF0YV90c190ZXN0LCBjb2w9InJlZCIpDQoNCg0KZGZfZXRzID0gYXMuZGF0YS5mcmFtZShmY3N0X2V0cykNCnByZWRpY3RfdmFsdWVfZXRzID0gZGZfZXRzJGBQb2ludCBGb3JlY2FzdGANCk1BUEUocHJlZGljdF92YWx1ZV9ldHMsIGRhdGFfdHNfdGVzdCkqMTAwDQoNCmBgYA0KDQojIyBNb2TDqGxlIEFSTUENCg0KDQpBIEZBSVJFDQoNCg0KIyMgTW9kw6hsZSBBUklNQSAvIFNBTUlSQSBBdXRvbWF0aXF1ZQ0KDQpBUklNQSA6IEF1dG9SZWdyZXNzaXZlIEludGVncmF0ZWQgTW92aW5nIEF2ZXJhZ2UNCg0KTGUgbW9kw6hsZSBBUklNQSBlc3QgdW5lIGNvbWJpbmFpc29uIGR1IG1vZMOobGUgQVJNQSBjb21iaW7DqSDDoCB1bmUgZGlmZsOpcmVudGlhdGlvbiAobGUgSW50ZWdyYXRlZCkNCg0KRGlmZsOpcmVudGlhdGlvbiA9IHLDqXRpcmVyIGxlcyB0ZW5kYW5jZXMgDQogIC0+IHRlbmRhbmNlIGxpbsOpYWlyZSA6IHVuZSBkaWZmw6lyZW5jaWF0aW9uIA0KICAtPiB0ZW5kYW5jZSBxdWFkcmFkaXF1ZSA6IGRldXggZGlmZsOpcmVuY2lhdGlvbnMgDQoNCkxlIG1vZMOobGUgU0FSSU1BIGVzdCB1bmUgY29tYmluYWlzb24gZHUgbW9kw6hsZSBBUklNQSBxdWkgcHJlbmQgZW4gY29tcHRlIGxhIGNvbXBvc2FudGUgc2Fpc29ubmlhaXJlLiANCg0KYXV0by5hcmltYSBwcmVuZCBlbiBjb21wdGUgbGVzIHNhaXNvbm5hbGl0w6lzLCBjb21tZSBvbiBwZXV0IGxlIHZvaXIgZGFucyBsZSBtb2TDqGxlIHNlbGVjdGlvbm7DqSA6DQooMCwxLDEpKDAsMSwxKVsxMl0NCg0KDQpgYGB7cn0NCiMgcmV0b3VybmUgbGVzIG1laWxsZXVycyBwYXJhbcOodHJlcyANCiMgZD0xIGVubGV2ZSBsYSB0ZW5kYW5jZQ0KIyBEPTEgZW5sZXZlIGxhIHNhaXNvbm5hbGl0w6kgDQojID0+IGF2b2lyIGRlcyBkb25uw6llcyBzdGF0aW9ubmFpcmVzDQojIHRyYWNlIDogdm9pciBsZXMgcsOpc3VsdGF0cw0KZml0X2FyaW1hIDwtIGF1dG8uYXJpbWEoZGF0YV90c190cmFpbiwgZD0xLCBEPTEsIHN0ZXB3aXNlID0gRkFMU0UsIGFwcHJveGltYXRpb24gPSBGQUxTRSwgdHJhY2U9VFJVRSkNCnByaW50KHN1bW1hcnkoZml0X2FyaW1hKSkNCmNoZWNrcmVzaWR1YWxzKGZpdF9hcmltYSkNCmBgYA0KDQpgYGB7cn0NCmZjc3RfYXJpbWEgPC0gZm9yZWNhc3QoZml0X2FyaW1hLCBoPTgpDQpwbG90KGZjc3RfYXJpbWEpDQpsaW5lcyhkYXRhX3RzX3Rlc3QsIGNvbD0ncmVkJykNCg0KDQpkZl9hcmltYSA9IGFzLmRhdGEuZnJhbWUoZmNzdF9hcmltYSkNCnByZWRpY3RfdmFsdWVfYXJpbWEgPSBkZl9hcmltYSRgUG9pbnQgRm9yZWNhc3RgDQpNQVBFKHByZWRpY3RfdmFsdWVfYXJpbWEsIGRhdGFfdHNfdGVzdCkqMTAwDQpgYGANCg0KDQoNCiMjIFBST1BIRVQNCg0KUHLDqXBhcmF0aW9uIGRvbm7DqWVzDQpgYGB7cn0NCmxpYnJhcnkoem9vKQ0KZGF0YV90cmFpbiRkcyA8LSBhcy5EYXRlKCBhcy55ZWFybW9uKHRpbWUoZGF0YV90c190cmFpbikpKQ0KYGBgDQoNCg0KDQpBIENPTU1FTlRFUiBFVCBBIEZBSVJFIEZPTkNUSU9OTkVSIFNVUlRUIChjaGFuZ2VtZW50IGRlIGxhIGZvcm1lIGRlcyBkYXRlcz8pDQpgYGB7cn0NCmxpYnJhcnkocHJvcGhldCkNCm1vZGVsX3Byb3BoZXQgPC0gcHJvcGhldChkYXRhX3RyYWluKQ0KZm9yZWNhc3RfcHJvcGhldCA8LSBtYWtlX2Z1dHVyZV9kYXRhZnJhbWUobW9kZWxfcHJvcGhldCwgcGVyaW9kcyA9IDgsIGZyZXEgPSAnbW9udGgnKQ0KQUFQTGZjIDwtIHByZWRpY3QobW9kZWxfcHJvcGhldCwgZm9yZWNhc3RfcHJvcGhldCkNCnRhaWwoQUFQTGZjW2MoImRzIiwgInloYXQiLCAieWhhdF9sb3dlciIsICJ5aGF0IildKQ0KDQoNCmR5cGxvdC5wcm9waGV0KG1vZGVsX3Byb3BoZXQsIEFBUExmYykNCg0KDQoNCmRhdGFfcHAgPC0gc3Vic2V0KEFBUExmYywgc2VsZWN0PWMoInloYXQiKSkNCmRhdGFfcHBfdHMgPC0gdHMoZGF0YV90dHR0LCBzdGFydD0yMDExLCBmcmVxdWVuY3k9MTIpDQpkYXRhX3BwX3RzX3cgPC0gd2luZG93KGRhdGFfcHBfdHMsIHN0YXJ0PSBjKDIwMTksMSksIGVuZCA9IGMoMjAxOSw4KSkNCg0KDQoNCnBsb3QoZGF0YV90cykNCmxpbmVzKGRhdGFfcHBfdHNfdywgY29sPSJyZWQiKQ0KDQpNQVBFKGRhdGFfcHBfdHNfdywgZGF0YV90c190ZXN0KSoxMDANCg0KDQpgYGANCg0KDQoNCg0KDQojIyBMU1RNIA0KDQpgYGB7cn0NCg0Kc2NhbGVfZmFjdG9ycyA8LSBjKG1lYW4oZGF0YSR5KSwgc2QoZGF0YSR5KSkNCnNjYWxlZF90cmFpbiA8LSBkYXRhICU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoeSkgJT4lDQogICAgZHBseXI6Om11dGF0ZSh5ID0gKHkgLSBzY2FsZV9mYWN0b3JzWzFdKSAvIHNjYWxlX2ZhY3RvcnNbMl0pDQpzY2FsZWRfdHJhaW4NCg0KDQoNCnByZWRpY3Rpb24gPC0gMTINCmxhZyA8LSBwcmVkaWN0aW9uDQpgYGANCk9uIHZldXQgcHJlbmRyZSBsJ2FubsOpZSBwcsOpY2VkZW50ZSBwb3VyIGFwcHJlbmRyZSA+IGxhZyBkZSAxMiwNCmVuIHLDqWFsaXTDqSBjYSBmYWl0IDEyIC0gMSBwb3VyIGF2b2lyIMOgIGNoYXF1ZSBwcsOpZGljdGlvbiBiYXPDqWUgc3VyIDEyIHZhbGV1cnMNCg0KcHVpcyBlbiB0cmFuc2Zvcm1lIGVuIGFycmF5IDNEIGNhciBsZSBtb2TDqGxlIExTVE0gcHJlbmRyZSB1biB0ZW5zb3IgZGUgZm9ybWF0IDNEIFtzYW1wbGVzLCB0aW1lc3RlcHMsIGZlYXR1cmVzXQ0KICBzYW1wbGVzIDogbmJyIGQnb2JzZXJ2YXRpb24gcGFyIGJhdGNocw0KICB0aW1lc3RlcHMgOiBsYWcNCiAgZmVhdHVyZXMgOiBuYnIgZGUgdmFsZXVyIHByZWRpdGVzIA0KDQoNCmBgYHtyfQ0Kc2NhbGVkX3RyYWluIDwtIGFzLm1hdHJpeChzY2FsZWRfdHJhaW4pDQogDQojIHdlIGxhZyB0aGUgZGF0YSAxMSB0aW1lcyBhbmQgYXJyYW5nZSB0aGF0IGludG8gY29sdW1ucw0KeF90cmFpbl9kYXRhIDwtIHQoc2FwcGx5KA0KICAgIDE6KGxlbmd0aChzY2FsZWRfdHJhaW4pIC0gbGFnIC0gcHJlZGljdGlvbiArIDEpLA0KICAgIGZ1bmN0aW9uKHgpIHNjYWxlZF90cmFpblt4Oih4ICsgbGFnIC0gMSksIDFdDQogICkpDQogDQojIG5vdyB3ZSB0cmFuc2Zvcm0gaXQgaW50byAzRCBmb3JtDQp4X3RyYWluX2FyciA8LSBhcnJheSgNCiAgICBkYXRhID0gYXMubnVtZXJpYyh1bmxpc3QoeF90cmFpbl9kYXRhKSksDQogICAgZGltID0gYygNCiAgICAgICAgbnJvdyh4X3RyYWluX2RhdGEpLA0KICAgICAgICBsYWcsDQogICAgICAgIDENCiAgICApDQopDQoNCiMoeF90cmFpbl9kYXRhKQ0KI2xlbmd0aCh4X3RyYWluX2FycikNCiNoZWFkKHhfdHJhaW5fYXJyKQ0KYGBgDQoNCg0KYGBge3J9DQp5X3RyYWluX2RhdGEgPC0gdChzYXBwbHkoDQogICAgKDEgKyBsYWcpOihsZW5ndGgoc2NhbGVkX3RyYWluKSAtIHByZWRpY3Rpb24gKyAxKSwNCiAgICBmdW5jdGlvbih4KSBzY2FsZWRfdHJhaW5beDooeCArIHByZWRpY3Rpb24gLSAxKV0NCikpDQoNCnlfdHJhaW5fYXJyIDwtIGFycmF5KA0KICAgIGRhdGEgPSBhcy5udW1lcmljKHVubGlzdCh5X3RyYWluX2RhdGEpKSwNCiAgICBkaW0gPSBjKA0KICAgICAgICBucm93KHlfdHJhaW5fZGF0YSksDQogICAgICAgIHByZWRpY3Rpb24sDQogICAgICAgIDENCiAgICApDQopDQoNCiNoZWFkKHlfdHJhaW5fZGF0YSkNCiNoZWFkKHlfdHJhaW5fYXJyKQ0KYGBgDQoNCg0KYGBge3J9DQp4X3Rlc3QgPC0gZGF0YSR5Wyhucm93KHNjYWxlZF90cmFpbikgLSBwcmVkaWN0aW9uICsgMSk6bnJvdyhzY2FsZWRfdHJhaW4pXQ0KDQp4X3Rlc3Rfc2NhbGVkIDwtICh4X3Rlc3QgLSBzY2FsZV9mYWN0b3JzWzFdKSAvIHNjYWxlX2ZhY3RvcnNbMl0NCg0KeF9wcmVkX2FyciA8LSBhcnJheSgNCiAgICBkYXRhID0geF90ZXN0X3NjYWxlZCwNCiAgICBkaW0gPSBjKA0KICAgICAgICAxLA0KICAgICAgICBsYWcsDQogICAgICAgIDENCiAgICApDQopDQoNCmBgYA0KDQoNCmBgYHtyfQ0KbHN0bV9tb2RlbCA8LSBrZXJhc19tb2RlbF9zZXF1ZW50aWFsKCkNCg0KbHN0bV9tb2RlbCAlPiUNCiAgbGF5ZXJfbHN0bSh1bml0cyA9IDUwLCAjIHNpemUgb2YgdGhlIGxheWVyDQogICAgICAgYmF0Y2hfaW5wdXRfc2hhcGUgPSBjKDEsIDEyLCAxKSwgIyBiYXRjaCBzaXplLCB0aW1lc3RlcHMsIGZlYXR1cmVzDQogICAgICAgcmV0dXJuX3NlcXVlbmNlcyA9IFRSVUUsDQogICAgICAgc3RhdGVmdWwgPSBUUlVFKSAlPiUNCiAgIyBmcmFjdGlvbiBvZiB0aGUgdW5pdHMgdG8gZHJvcCBmb3IgdGhlIGxpbmVhciB0cmFuc2Zvcm1hdGlvbiBvZiB0aGUgaW5wdXRzDQogIGxheWVyX2Ryb3BvdXQocmF0ZSA9IDAuNSkgJT4lDQogIGxheWVyX2xzdG0odW5pdHMgPSA1MCwNCiAgICAgICAgcmV0dXJuX3NlcXVlbmNlcyA9IFRSVUUsDQogICAgICAgIHN0YXRlZnVsID0gVFJVRSkgJT4lDQogIGxheWVyX2Ryb3BvdXQocmF0ZSA9IDAuNSkgJT4lDQogIHRpbWVfZGlzdHJpYnV0ZWQoa2VyYXM6OmxheWVyX2RlbnNlKHVuaXRzID0gMSkpDQoNCmxzdG1fbW9kZWwgJT4lDQogICAgY29tcGlsZShsb3NzID0gJ21hZScsIG9wdGltaXplciA9ICdhZGFtJywgbWV0cmljcyA9ICdhY2N1cmFjeScpDQoNCnN1bW1hcnkobHN0bV9tb2RlbCkNCg0KDQpgYGANCg0KYGBge3J9DQpsc3RtX21vZGVsICU+JSBmaXQoDQogICAgeCA9IHhfdHJhaW5fYXJyLA0KICAgIHkgPSB5X3RyYWluX2FyciwNCiAgICBiYXRjaF9zaXplID0gMSwNCiAgICBlcG9jaHMgPSAyMCwNCiAgICB2ZXJib3NlID0gMSwNCiAgICBzaHVmZmxlID0gRkFMU0UNCikNCmBgYA0KDQpgYGB7cn0NCmxzdG1fZm9yZWNhc3QgPC0gbHN0bV9tb2RlbCAlPiUNCiAgICBwcmVkaWN0KHhfcHJlZF9hcnIsIGJhdGNoX3NpemUgPSAxKSAlPiUNCiAgICAuWywgLCAxXQ0KIA0KIyByZXNjYWxlIGVuIGZvcm1hdCBiYXNpcXVlDQpsc3RtX2ZvcmVjYXN0IDwtIGxzdG1fZm9yZWNhc3QgKiBzY2FsZV9mYWN0b3JzWzJdICsgc2NhbGVfZmFjdG9yc1sxXQ0KbHN0bV9mb3JlY2FzdA0KYGBgDQoNCg0KIFggcsOpc3VsdGF0cyAvIHByw6lkaWN0aW9ucyBwYXIgaW5wdXQgZG9uYyA+IHRyYW5zZm9ybWUgcG91ciB1bmUgc2V1bGUgcHLDqWRpY2l0b24NCmBgYHtyfQ0KZml0dGVkIDwtIHByZWRpY3QobHN0bV9tb2RlbCwgeF90cmFpbl9hcnIsIGJhdGNoX3NpemUgPSAxKSAlPiUNCiAgICAgLlssICwgMV0NCg0KaWYgKGRpbShmaXR0ZWQpWzJdID4gMSkgew0KICAgIGZpdCA8LSBjKGZpdHRlZFssIDFdLCBmaXR0ZWRbZGltKGZpdHRlZClbMV0sIDI6ZGltKGZpdHRlZClbMl1dKQ0KfSBlbHNlIHsNCiAgICBmaXQgPC0gZml0dGVkWywgMV0NCn0NCg0KIyByZXNjYWxlIGZpbmFsIGRlIG5vcyBkb25uw6llcw0KZml0dGVkIDwtIGZpdCAqIHNjYWxlX2ZhY3RvcnNbMl0gKyBzY2FsZV9mYWN0b3JzWzFdDQpmaXR0ZWQNCmZpdHRlZCA8LSBjKHJlcChOQSwgbGFnKSwgZml0dGVkKQ0KZml0dGVkDQpsZW5ndGgoZml0dGVkKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KbHN0bV9mb3JlY2FzdCA8LSB0cyhsc3RtX2ZvcmVjYXN0LA0KICAgIHN0YXJ0ID0gYygyMDE5LCAxKSwNCiAgICBlbmQgPSBjKDIwMTksIDEyKSwNCiAgICBmcmVxdWVuY3kgPSAxMg0KKQ0KDQpsc3RtX2ZvcmVjYXN0X2Rpc3BsYXkgPC0gd2luZG93KGxzdG1fZm9yZWNhc3QsIHN0YXJ0PSBjKDIwMTksMSksIGVuZCA9IGMoMjAxOSw4KSkNCg0KaW5wdXRfdHMgPC0gdHMoZGF0YSR5LCANCiAgICBzdGFydCA9IGMoMjAxMSwgMSksIA0KICAgIGVuZCA9IGMoMjAxOCwgMTIpLCANCiAgICBmcmVxdWVuY3kgPSAxMikNCg0KDQpsc3RtX2ZvcmVjYXN0X2Rpc3BsYXkNCmRhdGFfdHNfdGVzdA0KDQpwbG90KGlucHV0X3RzLCB4bGltPWMoMjAxMSwyMDIwKSkNCiNsaW5lcyhkYXRhX3RzX3Rlc3QpDQpsaW5lcyhsc3RtX2ZvcmVjYXN0X2Rpc3BsYXksIGNvbD0zKQ0KDQoNCg0KYGBgDQoNCg==